GridLayout+Decoration 間距問題

眾所周知,要給RecyclerView中的Item加間距,有兩種比較通用的方式:

  • 直接在item的布局中加入間距
  • 給RecyclerView添加ItemDecoration來處理間距

第一種方式很直白,就是每個(gè)item之間其實(shí)沒有間距,是通過在每個(gè)item內(nèi)部處理顯示內(nèi)容和邊界處手動加空白,這樣看起來就像是有了間距一樣。而第二種方式,表面看起來也是很簡單的:間距多少直接填多少就好了嘛,有什么難的。但是實(shí)際使用時(shí)呢,會有奇怪的問題。

舉個(gè)栗子

一個(gè)簡單的需求,要給一個(gè)N行3列的RecyclerView加間距,每個(gè)Item之間間距10,然后靠邊的距離屏幕邊距是0,即緊貼屏幕,這樣寫:


addItemDecoration(object : RecyclerView.ItemDecoration() {
               override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                     val pos = parent.getChildAdapterPosition(view)
                   val column = (pos % span)
                   
                   outRect.left = 5
                   outRect.right = 5
                   outRect.top = 5
                   outRect.bottom = 5
                   
                   if (column == 0){
                       outRect.left = 0
                   }
                   if (column == 2){
                       outRect.right = 0
                   }
               }
           })

看起來好像沒問題?第一列的左邊距都是0,第三列的右邊距都是0,除此之外邊所有Item的左右間距剛好是 5+5=10,是這樣嗎?看看效果

image

很明顯,中間的item變小了,這是ItemDecoration繪制原理上導(dǎo)致的。因?yàn)镮tem首先是均等分布,且Item內(nèi)部顯示的內(nèi)容部分并不是完全居中,然后繪制計(jì)算的這個(gè)過程,又是從左向右一一計(jì)算的。所以越往后計(jì)算會把距離拉大,雖然看起來間距是正常的,但是因?yàn)榭娠@示內(nèi)容部分的寬度被擠壓了,所以顯得中間部分可顯示區(qū)域變小了。

怎么解決呢?也很簡單,在這個(gè)例子中,對于每一行來說,只有兩部分間距,即第一列的Item和第二列的Item間有一個(gè)間距,第二列Item跟第三列Item之間也有一個(gè)間距。而左右兩側(cè)距離屏幕距離是0,所以得出這一行中除了可顯示內(nèi)容View之外,剩下的需要留白的寬度是10+10=20。然后,因?yàn)橐恍惺侨?,所以對于每一個(gè)Item來說,他所分得的空白寬度,就是20/3。那么對第一列Item來說,他的左側(cè)距離是0(靠左側(cè)屏幕),那么右側(cè)距離就是 20/3-0=20/3。第二列,他的左側(cè)距離是多少呢?想一下,他的左側(cè)距離再加上第一列Item的右側(cè)距離,剛好就是10,既然已經(jīng)知道了第一列Item的右側(cè)間距,那么第二列Item的左側(cè)距離就是10-20/3=10/3,那他這個(gè)Item當(dāng)前還剩下的空白距離,就是20/3-10/3,也就是10/3。那第三列Item的左側(cè)邊距,同理可得為10-10/3=20/3,右側(cè)距離為20/3-20/3,剛好是0,代碼如下:


addItemDecoration(object : RecyclerView.ItemDecoration() {
               override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                   val pos = parent.getChildAdapterPosition(view)
                   val column = (pos % span)
                   
                   if (column == 0) { //第一列
                       outRect.left = 0
                       outRect.right = 20/3
                   } else if (column == 1) { //第二列
                       outRect.left = 10/3
                       outRect.right = 10/3
                   } else { //第三列
                       outRect.left = 20/3
                       outRect.right = 0
                   }

                   outRect.top = 5
                   outRect.bottom = 5
               }
           })

這樣效果就完美了:

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容