转载自fatchao的博客
地址:http://www.jianshu.com/p/5864db231ed5
最近项目中需要实现一个分类页面
UI图
列表联动UI
实现要求
左侧联动右侧:
点击左侧列表的某一项,背景变色,同时右侧列表中对应的分类滚动到顶部
右侧列表悬停:
右侧列表滑动的时候相应的标题栏需要在顶部悬停
标题栏可点击
右侧联动左侧:
滚动右侧列表,监听滚动的位置,左侧列表需要同步选中相应的列表
效果图
列表联动效果图
对照着上面的UI要求,基本上实现了所有的需求,下面分享一下实现的思路
左侧联动右侧
两侧都是Recyclerview,一开始以为就是调用一下Recyclerview的scrollToPostion滚动到具体的位置就好,但是实际上并非如此,因为Recyclerview的滚动方法有两种
scrollToPosition(int)
但是实际上调用的时候就比较坑爹,分为两种情况
从上往下滚动
如果是从上往下滚动的时候,发现每次达不到预期的效果,只能将需要滚动的item的显示出来而已,并不能滚动到顶部
从下滚动
这种情况是OK的,每次能够达到想要的效果
scrollBy(int x,int y)
这个方法如果是针对LinearLayoutManager的话,可以动态计算滚动的高度,但是针对相对复杂的布局就非常麻烦,最后找到了一种解决方案:
滚动的position小于FirstVisibleItemPosition
直接调用scrollToPosition
mRv.smoothScrollToPosition(n);
滚动的position介于FirstVisibleItemPosition与LastVisibleItemPosition之间
获取需要滚动的position距离顶部的高度,然后调用scrollBy
inttop= mRv.getChildAt(n - firstItem).getTop(); mRv.smoothScrollBy(0,top);
滚动的position>LastVisibleItemPosition
先调用scrollToPosition将需要滚动的position显示出来,在滚动完成时进行监听,当滚动停止的时候,执行跟2中相同的操作,达到目的
整体代码如下
//通过滚动的类型来进行相应的滚动privatevoidsmoothMoveToPosition(intn){intfirstItem = mManager.findFirstVisibleItemPosition();intlastItem = mManager.findLastVisibleItemPosition();if(n <= firstItem) { mRv.smoothScrollToPosition(n); }elseif(n <= lastItem) {inttop = mRv.getChildAt(n - firstItem).getTop(); mRv.smoothScrollBy(0, top); }else{ mRv.smoothScrollToPosition(n); move =true; } }//监听第三种情况,滚动停止之后再次进行滚动privateclassRecyclerViewListenerextendsRecyclerView.OnScrollListener{@OverridepublicvoidonScrollStateChanged(RecyclerView recyclerView,intnewState){super.onScrollStateChanged(recyclerView, newState);if(move && newState == RecyclerView.SCROLL_STATE_IDLE) { move =false;intn = mIndex - mManager.findFirstVisibleItemPosition(); Log.d("n---->", String.valueOf(n));if(0<= n && n < mRv.getChildCount()) {inttop = mRv.getChildAt(n).getTop(); Log.d("top--->", String.valueOf(top)); mRv.smoothScrollBy(0, top); } } }@OverridepublicvoidonScrolled(RecyclerView recyclerView,intdx,intdy){super.onScrolled(recyclerView, dx, dy); } }
右侧列表悬停
之前有看过张旭童的关于利用itemDecoration来实现城市列表索引的博客,写的的确是挺好的,唯一遗憾的是itemDecoration实现的头部不支持点击,所以这里换了另外一种思路。
Sectioned实现方式
伪造一个头部,给一个标志,然后加入到已有的数据集合中,然后再Recyclerview的Adapter中针对此标志返回标题栏的布局,达到分组的目的
for (inti =0; i < data.length; i++) {SortBean titleBean = new SortBean(String.valueOf(i));titleBean.setTitle(true);//头部设置为true,默认为falsetitleBean.setTag(String.valueOf(i));mDatas.add(titleBean);for (intj =0; j < 10; j++) {SortBean sortBean = new SortBean(String.valueOf(i+"行"+ j +"个"));sortBean.setTag(String.valueOf(i));mDatas.add(sortBean);} } @Override protected int getLayoutId(intviewType) { return viewType ==0? R.layout.item_title : R.layout.item_classify_detail;} @Override public int getItemViewType(intposition) { return list.get(position).isTitle() ?0:1;}
悬停的实现
其实这个利用了itemDecoration,调用RecyclerView.ItemDecoration的onDrawOver中进行绘制一个跟Title一模一样的标题栏就好了,这样就把第一个Section覆盖了,看起
来好像是悬停的感觉
当发现下一个title顶上来的时候,将canvas向上平移,产生一种向上挤压的动画效果
if(null!=tag&& !tag.equals(suspensionTag)) {if(child.getHeight() + child.getTop() < mTitleHeight) { c.save(); flag =true; c.translate(0, child.getHeight() + child.getTop() mTitleHeight); } }
绘制悬停的头部
这里没有一个一个控件的进行绘制,因为单个绘制比较麻烦,所以直接绘制了整个布局,同时修改了布局中标题栏中的内容
View topTitleView = mInflater.inflate(R.layout.item_title,parent,false); TextView tvTitle = (TextView) topTitleView.findViewById(R.id.tv_title); tvTitle.setText("测试数据"+tag);//进行测量获取MeasureSpec:toDrawWidthSpec,toDrawHeightSpec,代码省略//依次调用 measure,layout,draw方法,将复杂头部显示在屏幕上。topTitleView.measure(toDrawWidthSpec, toDrawHeightSpec); topTitleView.layout(parent.getPaddingLeft(),parent.getPaddingTop(),parent.getPaddingLeft() + topTitleView.getMeasuredWidth(),parent.getPaddingTop() + topTitleView.getMeasuredHeight()); topTitleView.draw(c);//Canvas默认在视图顶部,无需平移,直接绘制
标题栏可点击
由于是采用的布局而不是itemDecoration的实现,所以所有的标题栏都是可以点击跳转的
右侧联动左侧
当右侧悬停的title内容发生变化的时候,通过一个接口进行回调左侧列表即可,比较简单,贴下代码:
if(!Objects.equals(tag, currentTag)) {Log.d("tag---->",String.valueOf(MainActivity.finalNumber)); currentTag =tag;Integerinteger=Integer.valueOf(currentTag); mCheckListener.check(integer,false); }
作者:fatchao
链接:http://www.jianshu.com/p/5864db231ed5
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。