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.至于效果图的箭头效果,这里本人是偷懒让设计切得图,不过效果还可以的