最近項目中發現,有時候recyclerView刷新了數據后,部分ItemView里的文字出現被截斷的問題,或者是如果textView支持過長打點的話,出現提前打點,也就是文字長度還未超出限定范圍就開始打點了。
android中,View的內容如果發生改變,導致內容超出當前View的寬高范圍,需要重新請求視圖樹進行測量和布局,也就是調用requestLayout。如TextView的setText方法,ImageView的setImageResource,View的setLayoutParams方法。
問題原因可能是textView的setText方法未引起視圖樹的重新測量和布局,嘗試在setText后,手動調用textView的requestLayout方法,請求刷新視圖樹。但是某些情況下,特別是首次刷新數據時候,還是會出現文字被剪斷問題。
考慮是否是textView向上請求requestLayout被某一個ViewGroup給攔截了。
先分析view的requestLayout是如何傳遞給RootViewImpl的。
view調用requestLayout之后,會調用parent布局的requestLayout,parent布局又會再調用其parent布局的requestLayout,遞歸直到ViewRootImpl,并把沿途經過的所有View都標記上PFLAG_FORCE_LAYOUT、PFLAG_INVALIDATED這兩個Flag,那么在下一次VSync(16ms一次)到來的時候,將會重新計算和布局所有標記了PFLAG_FORCE_LAYOUT的View,也就是onMeasure和onLayout方法將被調用,接著draw所有標記了PFLAG_INVALIDATED的View,也就是draw方法將被調用。
我重寫了textView的onLayout方法,發現,requestLayout后,textView的onLayout并沒有執行。
也就是說ViewRootImpl并沒有收到textView的requestLayout請求,所以說,是被某一個ViewGroup給攔截了。
之后,使用排除法,從視圖樹的頂部往下走,挨個調用requestLayout,看看它的onLayout方法是否執行,當嘗試到內部的那個recyclerView的時候,發現,其requestLayout也失效了,也就是說外層的RecyclerView消費了所有孩子View的requestLayout請求。
查看RecyclerView的requestLayout方法源碼:
public void requestLayout() { if(!this.mEatRequestLayout) { super.requestLayout(); } else { this.mLayoutRequestEaten = true; }}如果變量mEatRequestLayout為true的話,攔截requestLayout的向上傳遞。
如此一來,只要重寫外層recyclerView的requestLayout方法,在調用super.requestLayout方法之前,使用反射將mEatRequestLayout設置成false即可。
目前來看,沒出現其他問題。但是性能上可能會有一些問題,RecyclerView之所以要消費requestLayout請求,一定有其原因,具體還未進行分析。
新聞熱點
疑難解答