RecyclerView打造完美可点击的滑动导航栏

2017-06-22  本文已影响0人  Jey欧巴

前一阵子在做一个关于事件处理流程的导航栏,要求导航栏可点击跟踪.当时找遍了各大博客论坛,我想说效果各式各样的都有,但就是没找到我想要的效果,无路可走的时候想想还是自己写吧,于是开始了自定义导航栏的设计.
废话先不多说上效果图:


Screenshot_20170622-115128.png

然后是主要代码:

public class StepRecyclerView extends NormalRecyclerView {
  private String TAG = "msg---->>";

  private Scroller mScroller;
  private int mLastx = 0;
  private int mTargetPos = 0;
  public StepRecyclerView(Context context) {
      super(context);
      init(context);
  }

  public StepRecyclerView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init(context);
  }

  public StepRecyclerView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      init(context);
  }

  private void init(Context context){
      mScroller = new Scroller(context);
  }

  @Override
  public void computeScroll() {
      super.computeScroll();
      //computeScrollOffset返回true表示滚动还在继续,持续时间应该就是startScroll设置的时间
      if(mScroller!=null && mScroller.computeScrollOffset()){
          Log.d("msg---------->>", "getCurrX = " + mScroller.getCurrX());
          scrollBy(mLastx - mScroller.getCurrX(), 0);
          mLastx = mScroller.getCurrX();
          postInvalidate();//让系统继续重绘,则会继续重复执行computeScroll
      }
  }

  /**
   * 将指定item平滑移动到整个view的中间位置
   * @param position
   */
  public void smoothToCenter(int position){
      int parentWidth = getWidth();//获取父视图的宽度
      int childCount = getChildCount();//获取当前视图可见子view的总数
      //获取可视范围内的选项的头尾位置
      int firstvisiableposition = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
      int lastvisiableposition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();
      int count = ((LinearLayoutManager)getLayoutManager()).getItemCount();//获取item总数
      if (mTargetPos>count) return;
      mTargetPos = Math.max(0, Math.min(count - 1, position));//获取目标item的位置(参考listview中的smoothScrollToPosition方法)
      if (mTargetPos>lastvisiableposition||mTargetPos<firstvisiableposition){//目标item超出可视视图范围外
          scrollToPosition(position);//滑动到目标视图
          return;
      }
      View targetChild = getChildAt(mTargetPos-firstvisiableposition);//获取目标item在当前可见视图item集合中的位置
      int childLeftPx = targetChild.getLeft();//子view相对于父view的左边距
      int childRightPx = targetChild.getRight();//子view相对于父view的右边距

      int childWidth = targetChild.getWidth();
      int centerLeft = parentWidth/2-childWidth/2;//计算子view居中后相对于父view的左边距
      int centerRight = parentWidth/2+childWidth/2;//计算子view居中后相对于父view的右边距
      Log.i(TAG,"rv width:"+parentWidth+"   item width:"+childWidth+"   centerleft:"+centerLeft+"   centerRight:"+centerRight);
      if(childLeftPx>centerLeft){//子view左边距比居中view大(说明子view靠父view的右边,此时需要把子view向左平移
          //平移的起始位置就是子view的左边距,平移的距离就是两者之差
          mLastx = childLeftPx;
          mScroller.startScroll(childLeftPx,0,centerLeft-childLeftPx,0,600);//600为移动时长,可自行设定
          postInvalidate();
      }else if(childRightPx<centerRight){
          mLastx = childRightPx;
          mScroller.startScroll(childRightPx,0,centerRight-childRightPx,0,600);
          postInvalidate();
      }
  }
}

使用方法:
1.布局中使用:

<com.xbqcc.WestCar.view.StepRecyclerView
            android:id="@+id/rvStepView"
            android:layout_width="match_parent"
            android:layout_height="@dimen/main_menu_height" />

2.当然在Java文件中要设置它的布局为横向布局,这里也可以在自定义代码中设置,但是考虑到后面可能会做一个垂直的导航栏就没写,有需求的道友们可以自己手动加上,代码:

rvStepView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));

3.当外部点击上一步或者下一步的时候,调用smoothToCenter(int position)方法,传递当前执行步骤.该导航栏相应的步骤变成选中状态,并且自动滑动到屏幕中间
4.至于效果图的箭头效果,这里本人是偷懒让设计切得图,不过效果还可以的

上一篇下一篇

猜你喜欢

热点阅读