繼承RecyclerView.LayoutManager自定義兩行橫向排列的RecyclerView.LayoutManager

看完打造屬于你的LayoutManager - huachao1001的專欄 - 博客頻道 - CSDN.NET

編寫的育苟,再次感謝改博主。

public classMyGridLayoutextendsRecyclerView.LayoutManager {

privateActivitymActivity;

private inthorizontallyOffset=0;

private inttotalWidth=0;//控件的總寬度

//保存所有的Item的上下左右的偏移量信息

privateSparseArrayallItemFrames=newSparseArray<>();

//記錄Item是否出現(xiàn)過屏幕且還沒有回收博烂。true表示出現(xiàn)過屏幕上漱竖,并且還沒被回收

privateSparseBooleanArrayhasAttachedItems=newSparseBooleanArray();

publicMyGridLayout(Activity activity) {

this.mActivity= activity;

}

@Override

public voidonLayoutChildren(RecyclerView.Recycler recycler,RecyclerView.State state) {

//如果沒有item馍惹,直接返回

if(getItemCount() <=0)return;

//跳過preLayout,preLayout主要用于支持動畫

if(state.isPreLayout()) {

return;

}

//在布局之前悼吱,將所有的子View先Detach掉良狈,放入到Scrap緩存中

detachAndScrapAttachedViews(recycler);

/**

*定義橫、豎方向的偏移量

*/

intoffsetX =0;

intoffsetY =0;

totalWidth=0;//初始化寬度

intlins =1;//行

intcolumn =0;//頁

intlinNumber =0;

intnumber =0;

DisplayMetrics metric =newDisplayMetrics();

mActivity.getWindowManager().getDefaultDisplay().getMetrics(metric);

intmaxWidth = metric.widthPixels;//屏幕寬度(像素)

Log.d("[MyGridLayout]","maxWidth:"+ maxWidth);

Log.d("[MyGridLayout]","ItemCount:"+ getItemCount());

for(inti =0;i < getItemCount();i++) {

View scrap = recycler.getViewForPosition(i);//根據(jù)position獲取一個碎片view,可以從回收的view中獲取窥突,也可能新構(gòu)造一個

addView(scrap);

measureChildWithMargins(scrap,0,0);//計算此碎片view包含邊距的尺寸

intwidth = getDecoratedMeasuredWidth(scrap);//獲取此碎片view包含邊距和裝飾的寬度width

intheight = getDecoratedMeasuredHeight(scrap);//獲取此碎片view包含邊距和裝飾的高度height

linNumber = maxWidth / width;

/**

* view復(fù)用

*/

Rect frame =allItemFrames.get(i);

if(frame ==null) {

frame =newRect();

}

if(number >= linNumber) {//第二行

if(number == linNumber) offsetX = offsetX - linNumber * width;

//最后阻问,將View布局到RecyclerView容器中

//? ? ? ? ? ? ? ? layoutDecorated(scrap, offsetX, height, offsetX + width, height * 2);

frame.set(offsetX,height,offsetX + width,height *2);

offsetX += width;

if(number == (linNumber *2-1)) {

number =0;

column++;

}else{

number++;

}

}else{//第一行

//最后,將View布局到RecyclerView容器中

//? ? ? ? ? ? ? ? layoutDecorated(scrap, offsetX, offsetY, offsetX + width, height);

frame.set(offsetX,offsetY,offsetX + width,height);

offsetX += width;

number++;

}

/**

* view復(fù)用

*/

//將當前的Item的Rect邊界數(shù)據(jù)保存

allItemFrames.put(i,frame);

//由于已經(jīng)調(diào)用了detachAndScrapAttachedViews第队,因此需要將當前的Item設(shè)置為未出現(xiàn)過

hasAttachedItems.put(i, false);

//第一行? 第二行

totalWidth= number < linNumber ? offsetX : column * width * linNumber - (maxWidth - linNumber * width);

}

Log.d("[MyGridLayout]","totalWidth-1:"+totalWidth);

//如果所有子View的高度和沒有填滿RecyclerView的高度凳谦,

//則將高度設(shè)置為RecyclerView的高度

totalWidth= Math.max(totalWidth,getHorizontallySpace());

Log.d("[MyGridLayout]","totalWidth-2:"+totalWidth);

/**

* view復(fù)用

*/

recycleAndFillItems(recycler,state);

}

@Override

publicRecyclerView.LayoutParamsgenerateDefaultLayoutParams() {

return newRecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,

ViewGroup.LayoutParams.WRAP_CONTENT);

}

@Override

public booleancanScrollHorizontally() {

return true;

}

@Override

public intscrollHorizontallyBy(intdx,RecyclerView.Recycler recycler,RecyclerView.State state) {

//先detach掉所有的子View

detachAndScrapAttachedViews(recycler);

//實際要滑動的距離

inttravel = dx;

Log.d("[MyGridLayout]","travel:"+ travel);

//如果滑動到最頂部

if(horizontallyOffset+ dx <0) {

travel = -horizontallyOffset;

}else if(horizontallyOffset+ dx >totalWidth) {//如果滑動到最底部horizontallyOffset + dx > totalWidth - getHorizontallySpace()

//? ? ? ? ? ? travel = totalWidth - getHorizontallySpace() - horizontallyOffset;

travel =totalWidth-horizontallyOffset;

}

//將橫向的偏移量+travel

horizontallyOffset+= travel;

Log.d("[MyGridLayout]","travel-1:"+ travel);

//平移容器內(nèi)的item

offsetChildrenHorizontal(-travel);

/**

* view復(fù)用

*/

recycleAndFillItems(recycler,state);

returntravel;

}

/**

*回收不需要的Item尸执,并且將需要顯示的Item從緩存中取出

*/

private voidrecycleAndFillItems(RecyclerView.Recycler recycler,RecyclerView.State state) {

if(state.isPreLayout()) {//跳過preLayout如失,preLayout主要用于支持動畫

return;

}

//當前scroll offset狀態(tài)下的顯示區(qū)域

Rect displayFrame =newRect(horizontallyOffset,0,horizontallyOffset+ getHorizontallySpace(),getVerticalSpace());

/**

*將滑出屏幕的Items回收到Recycle緩存中

*/

Rect childFrame =newRect();

for(inti =0;i < getChildCount();i++) {

View child = getChildAt(i);

childFrame.left= getDecoratedLeft(child);

childFrame.top= getDecoratedTop(child);

childFrame.right= getDecoratedRight(child);

childFrame.bottom= getDecoratedBottom(child);

//如果Item沒有在顯示區(qū)域,就說明需要回收

if(!Rect.intersects(displayFrame,childFrame)) {

//回收掉滑出屏幕的View

removeAndRecycleView(child,recycler);

}

}

//重新顯示需要出現(xiàn)在屏幕的子View

for(inti =0;i < getItemCount();i++) {

if(Rect.intersects(displayFrame,allItemFrames.get(i))) {

View scrap = recycler.getViewForPosition(i);

measureChildWithMargins(scrap,0,0);

addView(scrap);

Rect frame =allItemFrames.get(i);// -horizontallyOffset

//將這個item布局出來

layoutDecorated(scrap,

frame.left-horizontallyOffset,

frame.top,

frame.right-horizontallyOffset,

frame.bottom);

}

}

}

/**

*獲取RecyclerView在水平方向上的可用空間,

*即去除了padding后的高度

*/

private intgetHorizontallySpace() {

returngetWidth() - getPaddingLeft() - getPaddingRight();

}

/**

*獲取RecyclerView在豎直方向上的可用空間脆丁,

*即去除了padding后的高度

*/

private intgetVerticalSpace() {

returngetHeight() - getPaddingBottom() - getPaddingTop();

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偎快,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子裆馒,更是在濱河造成了極大的恐慌,老刑警劉巖丐怯,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喷好,死亡現(xiàn)場離奇詭異,居然都是意外死亡读跷,警方通過查閱死者的電腦和手機梗搅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來效览,“玉大人无切,你說我怎么就攤上這事∝ね鳎” “怎么了哆键?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵瘦锹,是天一觀的道長籍嘹。 經(jīng)常有香客問我闪盔,道長,這世上最難降的妖魔是什么辱士? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任泪掀,我火速辦了婚禮,結(jié)果婚禮上颂碘,老公的妹妹穿的比我還像新娘异赫。我一直安慰自己,他們只是感情好凭涂,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布祝辣。 她就那樣靜靜地躺著贴妻,像睡著了一般切油。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上名惩,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天澎胡,我揣著相機與錄音,去河邊找鬼娩鹉。 笑死攻谁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的弯予。 我是一名探鬼主播戚宦,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锈嫩!你這毒婦竟也來了受楼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤呼寸,失蹤者是張志新(化名)和其女友劉穎艳汽,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體对雪,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡河狐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瑟捣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馋艺。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖迈套,靈堂內(nèi)的尸體忽然破棺而出捐祠,到底是詐尸還是另有隱情,我是刑警寧澤交汤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布雏赦,位于F島的核電站劫笙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏星岗。R本人自食惡果不足惜填大,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俏橘。 院中可真熱鬧允华,春花似錦、人聲如沸寥掐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闭专。三九已至娃惯,卻和暖如春拉背,著一層夾襖步出監(jiān)牢的瞬間舌狗,已是汗流浹背葡兑。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工脸秽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秦驯,地道東北人衫贬。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓德澈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親固惯。 傳聞我的和親對象是個殘疾皇子梆造,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容