ListViewに基づいたカスタムコンポーネントの作成

Androidアプリケーションの場合、DatePickerにリモートで似たインターフェイス要素が必要でした。 彼はできる必要があります:



この種類のコンポーネントを取得する必要があります。





子ListViewを使用して、LinearLayoutからRollViewコンポーネントを継承します。 コンポーネント内に、OnScrollListenerインターフェイスを実装して、スクロール時のListViewの動作を決定します。

public class RollView extends LinearLayout implements OnScrollListener{ private final ListView innerListView; }
      
      







コンストラクターで、xmlファイルを使用してListViewを初期化し、リスナーを割り当てます。

データを表すには、オーバーライドされたgetView()メソッドで内部アダプターを作成します。

 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; } }
      
      







getViewメソッドからのすべてのビューは、パラメーターを変更するためにArrayListに書き込まれます。 refreshLayoutParams()メソッドは、表示されるアイテムの数に応じてリストアイテムのサイズを設定します。 アダプタクラスでは他に何もしません。



リストの最初の要素を中央に移動できるようにするには、配列の最初と最後に空の行を追加します。

次に、onScrollメソッドとonScrollStateChangedメソッドでスクロールを処理する必要があります。

 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); }
      
      







refreshTextViews()メソッドは、要素の位置に応じてテキストサイズと透明度を変更します。

 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); } }
      
      







テキストに影を追加するために残ります。 これを行うには、TextViewから継承したShadowTextViewコンポーネントを作成します。 影付きのテキストを描画するには、ブラシ(ペイント)を作成し、そのパラメーターを設定する必要があります。

ブラシオプション
プライベート最終ペイントmPaint =新しいペイント();

 //      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); }
      
      







onDraw()メソッドで、コンポーネントを再描画します。

 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); } }
      
      





RollViewから影を再描画するには、redraw()メソッドを追加します。

 public void redraw(){ text = getText().toString(); mPaint.setTextSize(getTextSize()); mPaint.getTextBounds(text, 0, getText().toString().length() , mBounds); invalidate(); }
      
      





あとは、TextViewをShadowTextViewに置き換え、refreshTextViewsメソッドでtv.redraw()メソッドを呼び出すだけです。

ここで、ユーザーが選択した値を取得するには、getCurrentItemValue()およびgetCurrentItemIndex()メソッドを追加するだけです。

作業の視覚的デモ:



完全なプロジェクトへのリンク:

https://bitbucket.org/msinchevskaya/rollview



All Articles