關於流逝佈局作業7.0顯示問題詳解
首先我們來看造成這個問題的原因:
那天在完成這組程式碼的時候,為了給大家體現可操作的自由性,我並沒有去給大家完善業務邏輯,所以造成了這個坑存在的問題,那麼我門首先來看造成這個問題的原因是什麼
首先看程式碼,我門採取的方式,是將測量後的程式碼用集合儲存起來再給layout進行佈局,
那麼參考原始碼
這裡呼叫兩次,而在低版本當中,,而用集合收集儲存兩次之後總行書數為6行,那麼這個問題深入分析後,做了一次測試
那麼從這兩張圖可以分析出,在7.0之後和7.0之前系統對於原始碼由一定程度的改變,
可以很明顯看到,27版本依賴於一個mReportNextDraw變數而這個變數在下面performDraw進行了一次變幻,這裡面執行流程比較複雜,有需要的同學自己深入,我們在這裡明白一點就是,layout呼叫被被了一層條件,第一次不執行, 第二次執行了reportNextDraw()過後才執行
從執行機制來講,在7.0之前圖1所呼叫的scheduleTraversals她會依次呼叫onMeasure-->onLayout,但是在7.0之後我門會發現執行機制發生了改變,如果是第一次的onMeasure那麼他不會去呼叫onLayout,所以這裡變成了兩次onMeasure一次onLayout 那麼這個時候在我們的List當中就會存在6行,當我講測量固定了一個大的值之後我們看到了效果
這裡可以很明顯看到其實子控制元件被我們定位到了3行開外超過了父控制元件的顯示高度
所以解決有兩種方案,第一種在onMeasure裡面新增clear()
第二種
我直接修改了原始碼不採用第三方的容器這裡我修改了佈局程式碼
public class WaterfallFLowLayout extends ViewGroup {
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attires
}
//思路,通過前面兩節課我門知道了其實,繪製流程最終會呼叫到我門的OnMesure 和 onLayout,
//而不通的佈局,他們自己的實現不一樣,所以才有了我門使用的這些基本佈局元件
//那麼我們現在自己來開發一個瀑布式的流式佈局
public WaterfallFLowLayout(Context context) {
super(context);
}
public WaterfallFLowLayout(Context context, AttributeSet attrs) {
super(context, attires
}
public WaterfallFLowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i("barry", "onMeasure.......");
//此處我門可以知道這裡是我們的爸爸的SIZE
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//當前空間寬高
int measureWidth = 0;
int measureHeight = 0;
//當前行寬,行高,因為存在多行,下一行資料要放到下方,行高需要儲存
int iCurLineW = 0;
int iCurLineH = 0;
//1.確認自己當前空間的寬高,這裡因為會有兩次OnMeasure,進行二級測量優化,所以採用IF_ELSE結構
//二級優化原理在原始碼具體Draw時,第一次不會直接進行performDraw的呼叫反而是在下面重新進行了一次scheduleTraversals
//在ViewRootImpl原始碼2349-2372之中我門會看到 scheduleTraversals在我們的2363
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
measureWidth = widthSize;
measureHeight = heightSize;
} else {
//當前VIEW寬高
int iChildWidth = 0;
int iChildHeight = 0;
//獲取子VIEW數量用於迭代
int childCount = getChildCount();
Log.i("barry", "childCount:" + childCount);
//單行資訊容器
for (int i = 0; i < childCount; i++) {
View childAt = getChildAt(i);
//1.測量自己
measureChild(childAt, widthMeasureSpec, heightMeasureSpec);
//2.獲取XML資源
MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();
//3.獲得實際寬度和高度(MARGIN+WIDTH)
iChildWidth = childAt.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
iChildHeight = childAt.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
Log.i("barry", "------widthSize-----:" + widthSize);
//4.是否需要換行
if (iCurLineW + iChildWidth > widthSize) {
//4.1.紀錄當前行資訊
//4.1.1.紀錄當前行最大寬度,高度累加
measureWidth = Math.max(measureWidth, iCurLineH);
measureHeight += iCurLineH;
Log.i("barry", "------height---換行--:" + measureHeight);
//4.1.2.儲存這一行資料,及行高
//4.2.紀錄新的行資訊
//4.2.1.賦予新行新的寬高
iCurLineW = iChildWidth;
iCurLineH = iChildHeight;
} else {
//5.1.不換行情況
//5.1.1.記錄某行內的訊息行內寬度的疊加、高度比較
iCurLineW += iChildWidth;
iCurLineH = Math.max(iCurLineH, iChildHeight);
}
//6.如果正好是最後一行需要換行
if (i == childCount - 1) {
//6.1.記錄當前行的最大寬度,高度累加
measureWidth = Math.max(measureWidth, iCurLineW);
measureHeight += iCurLineH;
}
}
}
Log.i("barry", "width:" + measureWidth);
Log.i("barry", "height:" + measureHeight);
//確認儲存自己的寬高
setMeasuredDimension(widthSize, measureHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.i("barry", "onLayout.....");
int startX = getPaddingLeft();
int startY = getPaddingTop();
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
//每個子控制元件佔據的寬度
int childViewUseWidth = 0;
int childViewUseLineHight = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
if (childView.getVisibility() == GONE) {
continue;
}
//獲取每個子控制元件的layoutParams
MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();
int childViewMeasuredWidth = childView.getMeasuredWidth();
int childViewMeasuredHeight = childView.getMeasuredHeight();
//startX 變化為0 就換行, 每個子控制元件在擺放之前,判斷剩餘控制元件是否足夠,用startX + childViewMeasuredWidth是否大於整個控制元件的寬度
//判斷的時候考慮PaddingRight
//考慮了子控制元件自己的margin值,每個子控制元件佔據的寬度:childViewMeasuredWidth + leftMargin + rightMargin
childViewUseWidth = childViewMeasuredWidth + layoutParams.leftMargin + layoutParams.rightMargin;
if (startX + /*childViewMeasuredWidth*/childViewUseWidth > measuredWidth - getPaddingRight()) {
startX = getPaddingLeft();
//換行的時候,上一行使用的高度以一行的最高的為準
startY += /*childViewMeasuredHeight*/childViewUseLineHight; //y左邊累加,因為現在所有的子控制元件高度都一樣
}
//擺放子控制元件
int leftChildView = startX + layoutParams.leftMargin;//考慮自己的margin
int topChildView = startY + layoutParams.topMargin;
int rightChildView = leftChildView + childViewMeasuredWidth;
int bottomChildView = topChildView + childViewMeasuredHeight;
//子控制元件佈局
childView.layout(leftChildView, topChildView, rightChildView, bottomChildView);
//子控制元件擺放之後累加startX的值, 考慮每個孩子佔據的寬度要加上marginLeft , marginRingt
startX += /*childViewMeasuredWidth*/childViewUseWidth;
//計算每一行使用的高度
childViewUseLineHight = Math.max(childViewUseLineHight, childViewMeasuredHeight + layoutParams.topMargin + layoutParams.bottomMargin);
}
}
相關文章
- 關於rem佈局問題REM
- Python詞雲庫wordcloud中文顯示問題詳解PythonCloud
- 關於css佈局、居中的問題以及一些小技巧CSS
- Flutter 佈局詳解Flutter
- 關於把豎向單個佈局在鴻蒙等摺疊手機屏中顯示成雙向佈局鴻蒙
- 關於linux切換使用者只顯示$的問題Linux
- CSS關於flex佈局CSSFlex
- Android FlexboxLayout 佈局詳解AndroidFlex
- 關於Spyder在高解析度顯示器下的選單圖示顯示不正確問題
- Flutter佈局篇(1)–水平和垂直佈局詳解Flutter
- Flutter佈局篇(1)--水平和垂直佈局詳解Flutter
- 詳解CSS的Flex佈局CSSFlex
- Flutter Container Widget 佈局詳解FlutterAI
- Flutter 佈局(一)- Container詳解FlutterAI
- 詳解RecyclerView的預佈局View
- 關於IE下驗證碼圖片無法正常顯示問題
- archlinux下wps顯示問題解決方法Linux
- 關於flex佈局的應用Flex
- iOS自動佈局——Masonry詳解iOS
- CSS例項詳解:Flex佈局CSSFlex
- Flutter 佈局(七)- Row、Column詳解Flutter
- Flutter系列之Flex佈局詳解FlutterFlex
- 關於vue打包後scss檔案中背景圖片不顯示問題VueCSS
- UE4-關於列印到螢幕上沒有顯示的問題
- 關於 SAP ABAP 報表的多語言顯示問題試讀版
- 作業系統—生產者消費者問題詳解作業系統
- Flex佈局-垂直居中並換行顯示內容Flex
- 專業顯示卡和遊戲顯示卡的區別詳解 專業顯示卡和遊戲顯示卡哪個好?遊戲
- 關於響應式佈局,你必須要知道關於響應式佈局的幾件事
- CV關於Mysql中ON與Where區別問題詳解buaMySql
- ubuntu 16.04 nvidia顯示卡驅動相關問題Ubuntu
- LiveCharts中文顯示亂碼問題的解決Echarts
- Linux vscode右上角佈局按鈕顯示 & 頂部不顯示搜尋欄LinuxVSCode
- 關於微信小程式佈局排列微信小程式
- 【iOS】關於 UICollectionView 的自定義佈局iOSUIView
- [筆記]關於blade佈局的使用筆記
- Flutter 佈局(九)- Flow、Table、Wrap詳解Flutter
- Flutter 佈局(八)- Stack、IndexedStack、GridView詳解FlutterIndexView