AndroidはRecyclerViewを使って水平スクロールコントロールを実現します。


前言
Androidスクロールコントロールの実現方法はたくさんあると思います。RecyclerViewを使うのも簡単です。簡単な年齢スクロールコントロールを作って、RecyclerViewの使い方を見てみましょう。主に以下の点があります。
     (1)コントロールの中心位置をそろえます。
     (2)スクロール距離を計算します。
     (3)センタービューをハイライトします。
     (4)リアルタイムで中心データを表示する。
     (5)停止時に自動的に配置されます。
     (6)スクロール時にボタン状態スイッチを設定します。
効果

1.フレーム
主にRecyclerViewの部分ロジックに注目します。

 /**
  *         
  */
 private void initAgeList() {
  LinearLayoutManager mLayoutManager =
    new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
  mRvAgeList.setLayoutManager(mLayoutManager);
  mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
  mRvAgeList.setAdapter(mAgeAdapter);
  mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
   @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);

    mBDownStep.setEnabled(false);

    //         ,          
    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
     mAgeAdapter.highlightItem(getMiddlePosition());
     mRvAgeList.scrollToPosition(getScrollPosition());
     mLastValue = getMiddlePosition();
     UserInfoManager.setAge(getMiddlePosition() + START_NUM);

     mBDownStep.setEnabled(true); //       ,       
    }
   }

   @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    //       
    mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
   }
  });

  mAgeAdapter.highlightItem(getMiddlePosition());
 }
水平配置を設定

LinearLayoutManager mLayoutManager =
    new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
  mRvAgeList.setLayoutManager(mLayoutManager);
Adapterを追加し、開始と終了位置を設定します。

  mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
  mRvAgeList.setAdapter(mAgeAdapter);
2.Adapter
Adapterはセンター位置を示すように機能をカスタマイズして、データ連動表示、ハイライトItemなどを表示します。

/**
 *       
 * <p>
 * Created by wangchenlong on 15/11/12.
 */
public class PersonAgeAdapter extends RecyclerView.Adapter<PersonAgeAdapter.AgeItemViewHolder> {

 public static final int ITEM_NUM = 7; //      Item ,      

 private int mFrom; //   
 private int mTo; //   
 private int mHighlight = -1; //   

 public PersonAgeAdapter(int from, int to) {
  mFrom = from;
  mTo = to;
 }

 @Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  View item = LayoutInflater.from(parent.getContext()).
    inflate(R.layout.view_age_item, parent, false);

  //   Item   
  ViewGroup.LayoutParams lp = item.getLayoutParams();
  lp.width = getItemStdWidth();

  return new AgeItemViewHolder(item);
 }

 @Override public void onBindViewHolder(AgeItemViewHolder holder, int position) {
  holder.getTextView().setText(String.valueOf(mFrom + position));

  //     
  if (isSelected(position)) {
   holder.getTextView().setTextSize(30);
   holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black));
  } else {
   holder.getTextView().setTextSize(20);
   holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line));
  }
 }

 //     ,       
 public void highlightItem(int position) {
  mHighlight = position;
  int offset = ITEM_NUM / 2;
  for (int i = position - offset; i <= position + offset; ++i)
   notifyItemChanged(i);
 }

 //        
 public boolean isSelected(int position) {
  return mHighlight == position;
 }


 @Override public int getItemCount() {
  return mTo - mFrom + 1;
 }

 //       
 public static int getItemStdWidth() {
  DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics();
  return displayMetrics.widthPixels / ITEM_NUM;
 }

 // ViewHolder
 public class AgeItemViewHolder extends RecyclerView.ViewHolder {

  private TextView mTextView;

  public AgeItemViewHolder(View itemView) {
   super(itemView);

   mTextView = (TextView) itemView.findViewById(R.id.item_age_value);
   mTextView.setTag(this);
  }

  public TextView getTextView() {
   return mTextView;
  }
 }
}
各セルの幅は画面幅の奇数分の1で、スクリーンを塗りつぶすと、中心を指し始めます。

 @Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  View item = LayoutInflater.from(parent.getContext()).
    inflate(R.layout.view_age_item, parent, false);

  //   Item   
  ViewGroup.LayoutParams lp = item.getLayoutParams();
  lp.width = getItemStdWidth();

  return new AgeItemViewHolder(item);
 }
シングルItemの数は、センターのインジケータがセンターItemの中心を指す必要があります。
選択された状態に応じて、Itemスタイルを更新します。

 @Override public void onBindViewHolder(AgeItemViewHolder holder, int position) {
  holder.getTextView().setText(String.valueOf(mFrom + position));

  //     
  if (isSelected(position)) {
   holder.getTextView().setTextSize(30);
   holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black));
  } else {
   holder.getTextView().setTextSize(20);
   holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line));
  }
 }
ハイライトを設定し、センターの位置を明るくして、両側を回復して、AdapterにView Holderを再描画するように通知します。

 //     ,       
 public void highlightItem(int position) {
  mHighlight = position;
  int offset = ITEM_NUM / 2;
  for (int i = position - offset; i <= position + offset; ++i)
   notifyItemChanged(i);
 }

 //        
 public boolean isSelected(int position) {
  return mHighlight == position;
 }
notifyItemChanged()         .
取得幅は、1行の表示Itemの個数を単一の数に設定すると、中心は1つのItemを指す。

 //       
 public static int getItemStdWidth() {
  DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics();
  return displayMetrics.widthPixels / ITEM_NUM;
 }
注意RecyclerViewは半分のユニットを移動できません。ライン当たりの数がシングルの場合、必ずセンターを指します。
3.スクロールロジック
スクロール時に、リアルタイムでページ表示を更新します。停止時にハイライトとデータを更新します。スクロールが終了したら、ボタンをアクティブにします。

  mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
   @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    mBDownStep.setEnabled(false);

    //         ,          
    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
     mAgeAdapter.highlightItem(getMiddlePosition());
     mRvAgeList.scrollToPosition(getScrollPosition());
     mLastValue = getMiddlePosition();
     UserInfoManager.setAge(getMiddlePosition() + START_NUM);

     mBDownStep.setEnabled(true); //       ,       
    }
   }

   @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    //       
    mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
   }
  });

  mAgeAdapter.highlightItem(getMiddlePosition());
 }

 /**
  *       
  *
  * @return    
  */
 private int getMiddlePosition() {
  return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2);
 }

 /**
  *      ,      /       
  *
  * @return    
  */
 private int getScrollPosition() {
  return (int) ((double) mRvAgeList.computeHorizontalScrollOffset()
    / (double) PersonAgeAdapter.getItemStdWidth());
 }
スクロールの距離単位を判断して、総距離/単一Item幅をオフセットする。

 private int getScrollPosition() {
  return (int) ((double) mRvAgeList.computeHorizontalScrollOffset()
    / (double) PersonAgeAdapter.getItemStdWidth());
 }
computeHorizontalScrollOffset()は、RecyclerViewのシフト全体を取得する。
中間位置には、さらに半行Itemの数が追加されます。

 private int getMiddlePosition() {
  return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2);
 }
スクロールが止まるかどうかを判断します。

if (newState == RecyclerView.SCROLL_STATE_IDLE)
スクロールが停止した時、自動的に配置されます。

mRvAgeList.scrollToPosition(getScrollPosition());
呼び出しにはハイライトが必要なItem

mAgeAdapter.highlightItem(getMiddlePosition());
注意スクロール停止時に、ハイライトを更新したほうがいいです。でないと、再描画速度が遅くなり、スクロール効果に影響します。
スライド効果

締め括りをつける
はい、以上はこの文章の全部の内容です。これらによって様々なスクロールバーをカスタマイズできます。この文章が皆さんの役に立ちますように。