最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

DEVLOG 9.145 手寫一個RecyclerView總結(jié)

2021-09-14 20:18 作者:房頂上的鋁皮水塔  | 我要投稿

手寫RecyclerView的內(nèi)容參考了?手寫RecyclerView

歸納一下手寫RecyclerView中的一些重點和可能會遇到的面試題,這個總結(jié)主要談?wù)凴ecyclerView的設(shè)計、View的復(fù)用、View邊界判斷的思路。手寫的過程中遇到的問題也總結(jié)在這里:手寫RecyclerView問題總結(jié)

Github代碼連接:https://github.com/kolibreath/Practices/tree/master/MyRecyclerView

  1. 手寫RecyclerView設(shè)計思路

    1. MyRecyclerView繼承自ViewGroup

      手寫RecyclerView繼承自ViewGroup,眾所周知,ViewGroup是默認(rèn)設(shè)置了CLICKABLE 和 LONG_CLICKABLE = false,這樣一來onTouchEvent中的super就回返回false,所以最簡單的解決思路是在xml文件中設(shè)置MyRecyclerView的clickable=true。

    2. ViewGroup繪制的三大流程: onMeasure

      通常而言,ViewGroup首先應(yīng)該對子View進(jìn)行測量:調(diào)用measureChildren之類的方法測量子View。但是我們簡化的MyRecyclerView在初始化的時候并不知道子View的個數(shù),這個內(nèi)容是通過Adapter傳入的。所以我們的onMeasure沒有重寫:

? ? ?????測量工作可以在onLayout中執(zhí)行。我們默認(rèn)子View的高度為一個固定值,這樣比較方便。因為是指定的固定值,所以在測量的過程中我們設(shè)置測量模式為EXACTLY:

????

??

??????c.?ViewGroup繪制的三大流程: onLayout

????????在寫代碼之前我們應(yīng)當(dāng)思考一下onLayout需要執(zhí)行的任務(wù)

  1. 當(dāng)?shù)谝淮渭虞dData的時候,ViewGroup中沒有任何內(nèi)容,我們應(yīng)當(dāng)使用LayoutInflater加載View(先不考慮復(fù)用)。

  2. 使用LayoutInflater加載的View應(yīng)該被添加到ViewGroup中。(addView)但是LayoutInflater并不會產(chǎn)生寬高,因為寬高的產(chǎn)生需要結(jié)合LayoutParams+父容器的MeasureSpec(mode+size)。

  3. 第一次加載,沒有出現(xiàn)任何滑動行為時,我們通過屏幕的高度+View的高度推算應(yīng)該現(xiàn)實的View個數(shù)。

  4. 當(dāng)后續(xù)加載的過程中,先前顯示在ViewGroup中的內(nèi)容應(yīng)當(dāng)被清除

因此,我們可以得出以下的代碼:

但是,當(dāng)我們滑動的時候向上滑動或者向下滑動,View可能會被移除掉,被移除掉的View我們通過Recycler管理??紤]Recycler中保存View的數(shù)據(jù)結(jié)構(gòu),使用Stack是最為合理的。假設(shè)我們使用ArrayList,需要考慮ArrayList的擴(kuò)容行為;我們使用LinkedList,滑動手指過快,導(dǎo)致View被移除和補(bǔ)充得很快的時候,刪除和添加行為需要鏈接節(jié)點,也不是最優(yōu)的解決方案,所以使用Stack對于棧頂?shù)牟僮魇亲詈线m的。

如果我們支持多種不同的ViewType,我們就需要一個二維數(shù)組(棧)。


所以在上面的代碼makeAndSetupView(i, l,itemViewTop,r,itemViewBottom)?中我們通過obtain來獲取緩存的View。在得到這個View對象之后在進(jìn)行l(wèi)ayout。

這里我想說明一點,MyAdapter是我們實現(xiàn)的一個接口類,里面定義了很多回調(diào)函數(shù)。其中

onBindViewHolder還有onCreateViewHolder都應(yīng)該返回ViewHolder對象,但是我們?yōu)榱朔奖闫陂g直接返回View。 并且onBindViewHolder應(yīng)該是返回Unit(void),但是在這里如果返回Unit,還需要重新綁定一遍,我覺得也沒有必要,于是采用了視頻中的寫法。 這里還需要注意setTag的兩個小細(xì)節(jié):

  1. setTag的第一個參數(shù)int 會加載資源文件,所以不能給一個Int定值

  2. setTag使用<key-value>的模式,因為View.setTag也是非常常見的操作。如果在其他地方對于View進(jìn)行了setTag,在這里又進(jìn)行setTag,會改變預(yù)設(shè)的行為。

obtain獲取緩存的View。我們需要重寫removeView,以便存放View到Recycler中。

View的另外的draw流程讓View自行完成,這里就不說了。

onLayout只是一個靜態(tài)的行為,滑動的時候可以理解為滑動一點,onLayout一點。我們需要重寫消息處理機(jī)制,這里主要是重寫onInterceptTouchEvent和onTouchEvent。

  1. onInterceptTouchEvent:

    這個方法需要和onTouchEvent進(jìn)行配合。我們現(xiàn)在在一個ViewGroup中,要想onTouchEvent被執(zhí)行,我們需要返回true,表示不將消息交給子控件消費。當(dāng)滑動的動作超過touchSlop時返回true,這樣就會調(diào)用我們重寫的onTouchEvent:

? ?2. onTouchEvent:?

超過TouchSlop 我直接滑動:

3. 重寫ScrollBy?

因為scrollBy本身是通過調(diào)整canvas的位置進(jìn)行View的滑動,所以我們不能使用這個方法。我們必須要重寫。

重寫思路:

  1. 如果MyRecyclerView向上滑動,下面需要新的ItemView進(jìn)來補(bǔ)充,同時上面的View需要出去;向下滑動同理

  2. 如果MyRecyclerView向上滑動,但是已經(jīng)是第一個View了,控制不能上劃。同理,如果是最后一個View,我們不能下滑,所以我們可以定義scrollBound做邊界控制:

????3. 上劃需要從下面補(bǔ)充新的View;下滑需要從上面補(bǔ)充新的View,這也需要在scrollBy中實現(xiàn)。具體的邏輯我注釋在代碼中了:

滑動完成之后需要重新布局:


DEVLOG 9.145 手寫一個RecyclerView總結(jié)的評論 (共 條)

分享到微博請遵守國家法律
白银市| 深水埗区| 图们市| 平潭县| 内江市| 湖南省| 九龙县| 文登市| 开鲁县| 府谷县| 盐亭县| 佛学| 揭东县| 靖安县| 泸溪县| 东乌珠穆沁旗| 肃南| 新竹县| 府谷县| 凉山| 永靖县| 左贡县| 和龙市| 诏安县| 阿尔山市| 理塘县| 玉溪市| 建瓯市| 襄汾县| 潢川县| 尼木县| 印江| 芦山县| 宁蒗| 榆中县| 昆明市| 木里| 工布江达县| 鄂伦春自治旗| 湾仔区| 开封县|