最近比較忙,時(shí)間也是被碎片化了導(dǎo)致視頻一直沒有錄制,so 距離上一篇recyclerView系列文章已經(jīng)有挺久的了,小小的抱歉一下,接下里進(jìn)入我們的主題 自定義LayoutManager。
還記得在RecyclerView(3)- LayoutMagager源碼解析,LinearLayoutManager 當(dāng)中我們了解了調(diào)用recyler
類的回收/復(fù)用方法來減少view的創(chuàng)建與復(fù)用view,知道了layoutManage
按需加載布局view思路原理,總結(jié)了recylerView之所以如此高效性能的原因。
我們就要利用前幾章的知識(shí)來打造一個(gè) 自定義LayoutManager
,其中 復(fù)用view、按需加載布局、滑動(dòng)時(shí)按需加載view回收view;
效果如下:
可能有同學(xué)看到這里嗤之以鼻,這個(gè)還需要自定義layoutManager, 完全我自己自定義一個(gè)VIew就好了。 何必這么麻煩還要去繼承LayoutManager ?
我來解釋下原因:
1、本節(jié)是前幾章知識(shí)總結(jié)的產(chǎn)物,也就是說本章是前幾章知識(shí)的課后習(xí)題,所以我們要拿LayoutManager搞事情;
2、從性能方面考慮,這里細(xì)心的同學(xué)可能發(fā)現(xiàn)了,每次itemView滑出屏幕外又滑進(jìn)來 顏色是變了, 間接地說明了最起碼回收了view,按需加載布局(只顯示一頁布局的view);
3、我們要利用recyclerVIew的回收機(jī)制 來打造高性能自定義控件。
1、分析布局
1.1、 正常布局
1、我們根據(jù)行標(biāo)分為單雙行,雙行顯示3個(gè)元素,單行顯示兩個(gè)兩個(gè)元素。
2、下標(biāo)為0的 item ,的頂點(diǎn)位置為 0,0;
3、雙行 中item位置確定
表頭的位置: 如下圖
雙行中非表頭的item 位置比較好確定; 坐標(biāo)位置相比于上一個(gè)item x軸平移了一個(gè)item的寬度
4、單行itemView位置關(guān)系
單行的所有item 都是根據(jù)上一個(gè)itemVIew位置所確定的
1.2、 滑動(dòng)時(shí)布局
1.2.1、 上滑時(shí)布局
如上圖所示: 當(dāng)我上滑時(shí) 我需要回收 布局①中的內(nèi)容,添加布局②中的內(nèi)容,然后整體向上平移
1.2.2、 下滑時(shí)布局
如上圖所示 當(dāng)我下滑時(shí),我需要回收 布局②中的內(nèi)容,添加布局①中的內(nèi)容,然后整體向下平移
2、回顧知識(shí)
結(jié)合 LinearLayoutManager 源碼解析 提取我們需要用到的重點(diǎn)方法
// 1、入口:onLayoutChildren
// 2、回收所有view: removerRecyclerAllviews
// 回收單個(gè)或多個(gè)view : removeAndRecycleViewAt(i, recycler);
// 得到view : recycler.getviewForPositon
//
// 3、 允許滑動(dòng) canScrollerVertically() return true;
// 4、消耗滑動(dòng)距離 scrollerVertically( dy ...)
3、主線框架搭建
public class MyLayoutManager extends LayoutManager {
LayoutState layoutState = new LayoutState();
int rowCount = 4; //雙行的數(shù)量
public MyLayoutManager(int rowCount) {
this.rowCount = rowCount;
}
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
//回收所有的view
// 計(jì)算布局需要的各種數(shù)據(jù):
// 布局view 回收view
fill()
}
/**
* 填充view 回收view
*
* @param layoutState
* @param recycler
* @param state
* @return 實(shí)際消耗的偏移量 / 實(shí)際移動(dòng)的距離
*/
private int fill(LayoutState layoutState, RecyclerView.Recycler recycler, RecyclerView.State state) {
// 回收view
//添加view
// 自上而下填充
// 雙行
// 填充 下標(biāo)為0的view
// 填充 雙行 表頭view
// 填充 非行頭的view
// 單行
.// 填充單行表頭
//填充非行頭的view
// 自下而上填充
// 雙行
// 填充 雙行 行尾view
// 填充 非行尾的view
// 單行
.// 填充單行行尾
//填充非行尾的view
//計(jì)算消耗的偏移量 返回
return ;
}
@Override
public boolean canScrollVertically() {
return true;
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
// 根據(jù)偏移量 計(jì)算開始布局的坐標(biāo)點(diǎn) 各種數(shù)據(jù)
// 布局view 回收view
// 計(jì)算實(shí)際消耗的偏移量
// 平移children
//返回實(shí)際消耗的偏移量
return super.scrollVerticallyBy(dy, recycler, state);
}
/**
* Helper class that keeps temporary state while {LayoutManager} is filling out the empty
* space.
*/
static class LayoutState {
//布局的方向
int mItemDirection; // 1: 從上自下方向 -1 : 自下而上 方向
static final int downDirection = 1; //向上滑動(dòng),向下填充
static final int upDirection = -1; // 向下滑動(dòng),向上填充
// 開始填充的view的原點(diǎn)
Point startPoint = new Point(0, 0);
// 可用高度
int mAvailable;
/**
* Pixel offset where layout should start
*/
int mOffset;
/**
* Current position on the adapter to get the next item.
*/
public int mCurrentPosition;
public void initAndClear() {
startPoint.set(0, 0);
mAvailable = 0;
mOffset = 0;
mCurrentPosition = 0;
mItemDirection = downDirection;
}
}
}
好了 ,偽代碼寫好了,我們開始干活吧~~~
文章配套視頻地址在下方
· RecyclerView(1)- Decoration源碼解析
· RecyclerView(2)- 自定義Decoration打造時(shí)光軸效果
· RecyclerView(3)- LayoutMagager源碼解析,LinearLayoutManager
· RecyclerView(4)- 核心、Recycler復(fù)用機(jī)制_1
· RecyclerView(4)- 核心、Recycler復(fù)用機(jī)制_2
· RecyclerView(5)- 自定義LayoutManager(布局、復(fù)用)
· RecyclerView(6)- 自定義ItemAnimator
· RecyclerView(7)- ItemTouchHelper
· RecyclerView(8)- MultiTypeAdapter文章、MultiTypeAdapter Github地址
文章視頻地址:鏈接:http://pan.baidu.com/s/1hssvXC4 密碼:18v1
代碼地址在視頻筆記當(dāng)中
希望我的文章不會(huì)誤導(dǎo)在觀看的你,如果有異議的地方歡迎討論和指正。
如果能給觀看的你帶來收獲,那就是最好不過了。