📜 ⬆️ ⬇️

Creating a custom component based on a ListView

For an Android application, I needed an interface element, vaguely reminiscent of a DatePicker. He should be able to:

It should be a component of this type:


We will inherit our RollView component from LinearLayout with a ListView child element. Inside the component, we implement the OnScrollListener interface to define the ListView behavior when scrolling.
public class RollView extends LinearLayout implements OnScrollListener{ private final ListView innerListView; } 


In the constructor, initialize the ListView through the xml file and assign it to the listener.
To view the data, create an internal adapter with the overridden getView () method:
 private class RollAdapter extends ArrayAdapter<String> { private final LayoutInflater mInflater; @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null){ convertView = mInflater.inflate(R.layout.roll_view_adapter, null); convertView.setLayoutParams(mParams); } TextView tv = (TextView) convertView.findViewById(R.id.text); tv.setTag(position); //    tv.setText(getItem(position)); convertView.setTag(tv); //   TextView   if (!listViews.contains(convertView)) listViews.add(convertView); //        return convertView; } } 

')
All View from the getView method will be written to the ArrayList to change their parameters. The refreshLayoutParams () method sets sizes for list items depending on the number of visible items. We won't do anything else in the adapter class.

In order to be able to shift the first element of the list in the middle, add empty lines to the beginning and end of the array.
Now you need to handle scrolling in the onScroll and onScrollStateChanged methods:
 private int lastFirstVisibleElement; //   "  "     private int centralIndex; //     @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { refreshTextViews(); //     //    if (lastFirstVisibleElement > firstVisibleItem){ Log.i("RollView", "Scroll up"); } else if (lastFirstVisibleElement < firstVisibleItem){ Log.i("RollView", "Scroll down"); } lastFirstVisibleElement = firstVisibleItem; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //   if (scrollState == SCROLL_STATE_IDLE){ //  smoothScrollToPositionFromTop(centralIndex - totalElementVisible / 2 , 0, 1); } 


The refreshTextViews () method is responsible for changing the text size and transparency depending on the position of the element:
 public void refreshTextViews(){ float maxTextSize = 0; for (View v : listViews){ int centerOfViewY = v.getBottom() - (mAdapter.mParams.height / 2); ShadowTextView tv = (ShadowTextView) v.getTag(); float coefficient = (Math.abs(centerOfViewY - mAdapter.centerLineY)) / (float)mAdapter.centerLineY; float scale = 0; //   1 -      if (coefficient < 1) scale = Math.abs(coefficient - 1); tv.setAlpha(scale); //          float textSize = CENTRAL_TEXT_SIZE * scale; if (textSize > maxTextSize){ maxTextSize = textSize; centralIndex = (Integer) tv.getTag(); } tv.setTextSize(textSize); } } 


It remains to add a shadow for the text. To do this, create the ShadowTextView component inherited from TextView. To draw text with shadows, you need to create a brush (Paint) and set its parameters:
Brush options
private final Paint mPaint = new Paint ();
 //      private void initPaint(){ mPaint.setAntiAlias(true); mPaint.setTextSize(getTextSize()); mPaint.setColor(Color.WHITE); mPaint.setStrokeWidth(2.0f); mPaint.setStyle(Paint.Style.FILL); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setShadowLayer(10.0f, 0.0f, 0.0f, Color.BLACK); } 


and in the onDraw () method redraw the component:
 private final Rect mBounds = new Rect(); //   @Override protected void onDraw(Canvas canvas){ canvas.drawColor(Color.TRANSPARENT); int x = getWidth() / 2; int y = (getHeight() + mBounds.height()) / 2; canvas.drawText(getText().toString(), x, y, mPaint); } } 

To redraw the shadows from RollView, add the redraw () method:
 public void redraw(){ text = getText().toString(); mPaint.setTextSize(getTextSize()); mPaint.getTextBounds(text, 0, getText().toString().length() , mBounds); invalidate(); } 

It remains only to replace TextView in with ShadowTextView and call tv.redraw () method in the refreshTextViews method;
Now, to get the user-selected value, all that remains is to add the getCurrentItemValue () and getCurrentItemIndex () methods.
Visual demonstration of the work:

Link to the full project:
https://bitbucket.org/msinchevskaya/rollview

Source: https://habr.com/ru/post/225649/


All Articles