轉(zhuǎn)載自fatchao的博客
地址:http://www.reibang.com/p/5864db231ed5
最近項目中需要實現(xiàn)一個分類頁面
UI圖
列表聯(lián)動UI
實現(xiàn)要求
左側聯(lián)動右側:
點擊左側列表的某一項春塌,背景變色,同時右側列表中對應的分類滾動到頂部
右側列表懸停:
右側列表滑動的時候相應的標題欄需要在頂部懸停
標題欄可點擊
右側聯(lián)動左側:
滾動右側列表,監(jiān)聽滾動的位置陨溅,左側列表需要同步選中相應的列表
效果圖
列表聯(lián)動效果圖
對照著上面的UI要求实柠,基本上實現(xiàn)了所有的需求橱脸,下面分享一下實現(xiàn)的思路
左側聯(lián)動右側
兩側都是Recyclerview抒和,一開始以為就是調(diào)用一下Recyclerview的scrollToPostion滾動到具體的位置就好膳沽,但是實際上并非如此汗菜,因為Recyclerview的滾動方法有兩種
scrollToPosition(int)
但是實際上調(diào)用的時候就比較坑爹,分為兩種情況
從上往下滾動
如果是從上往下滾動的時候挑社,發(fā)現(xiàn)每次達不到預期的效果陨界,只能將需要滾動的item的顯示出來而已,并不能滾動到頂部
從下滾動
這種情況是OK的痛阻,每次能夠達到想要的效果
scrollBy(int x,int y)
這個方法如果是針對LinearLayoutManager的話菌瘪,可以動態(tài)計算滾動的高度,但是針對相對復雜的布局就非常麻煩阱当,最后找到了一種解決方案:
滾動的position小于FirstVisibleItemPosition
直接調(diào)用scrollToPosition
mRv.smoothScrollToPosition(n);
滾動的position介于FirstVisibleItemPosition與LastVisibleItemPosition之間
獲取需要滾動的position距離頂部的高度俏扩,然后調(diào)用scrollBy
inttop= mRv.getChildAt(n - firstItem).getTop();? ? mRv.smoothScrollBy(0,top);
滾動的position>LastVisibleItemPosition
先調(diào)用scrollToPosition將需要滾動的position顯示出來,在滾動完成時進行監(jiān)聽斗这,當滾動停止的時候动猬,執(zhí)行跟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;? ? ? ? }? ? }//監(jiān)聽第三種情況表箭,滾動停止之后再次進行滾動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來實現(xiàn)城市列表索引的博客赁咙,寫的的確是挺好的,唯一遺憾的是itemDecoration實現(xiàn)的頭部不支持點擊免钻,所以這里換了另外一種思路彼水。
Sectioned實現(xiàn)方式
偽造一個頭部,給一個標志,然后加入到已有的數(shù)據(jù)集合中极舔,然后再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;}
懸停的實現(xiàn)
其實這個利用了itemDecoration,調(diào)用RecyclerView.ItemDecoration的onDrawOver中進行繪制一個跟Title一模一樣的標題欄就好了拆魏,這樣就把第一個Section覆蓋了盯桦,看起
來好像是懸停的感覺
當發(fā)現(xiàn)下一個title頂上來的時候,將canvas向上平移渤刃,產(chǎn)生一種向上擠壓的動畫效果
if(null!=tag&& !tag.equals(suspensionTag)) {if(child.getHeight() + child.getTop() < mTitleHeight) {? ? ? ? ? ? ? ? ? ? c.save();? ? ? ? ? ? ? ? ? ? flag =true;? ? ? ? ? ? ? ? ? ? c.translate(0, child.getHeight() + child.getTop() mTitleHeight);? ? ? ? ? ? ? ? }? ? ? ? ? ? }
繪制懸停的頭部
這里沒有一個一個控件的進行繪制拥峦,因為單個繪制比較麻煩,所以直接繪制了整個布局卖子,同時修改了布局中標題欄中的內(nèi)容
View topTitleView = mInflater.inflate(R.layout.item_title,parent,false);? ? ? ? TextView tvTitle = (TextView) topTitleView.findViewById(R.id.tv_title);? ? ? ? tvTitle.setText("測試數(shù)據(jù)"+tag);//進行測量獲取MeasureSpec:toDrawWidthSpec略号,toDrawHeightSpec,代碼省略//依次調(diào)用 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的實現(xiàn)羽利,所以所有的標題欄都是可以點擊跳轉(zhuǎn)的
右側聯(lián)動左側
當右側懸停的title內(nèi)容發(fā)生變化的時候宫患,通過一個接口進行回調(diào)左側列表即可,比較簡單铐伴,貼下代碼:
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.reibang.com/p/5864db231ed5
來源:簡書
著作權歸作者所有撮奏。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權俏讹,非商業(yè)轉(zhuǎn)載請注明出處当宴。