自己寫一個流式佈局吧(FlowLayout)

(android)自己寫一個流式佈局吧(FlowLayout)

*首先我們要繼承ViewGroup 開發自定義佈局:


// 步驟一。繼承 ViewGroup 開發自定義佈局
public class FlowLayout extends ViewGroup {
private int layoutHeight;
private int layoutWidth;
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setBackgroundColor(Color.YELLOW);
}
public FlowLayout(Context context) {
this(context, null, 0);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

*測量是不可少的 查看有多少個元素

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//3.2. 測量前 清空行
mLines.clear();
//1.4 獲取所有子元素
int childCount = getChildCount();
//1.5 遍歷每個元素
Line curr = null;
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
//1.6 獲取子元素的測量寬高
child.measure(0, 0);// 測量包裹內容的寬高
int cWidth = child.getMeasuredWidth();
int cHeight = child.getMeasuredHeight();
System.out.println(“i->” + i + ” (” + cWidth + “,” + cHeight + “)”);
// 分行判斷 步驟三。
}
步驟二 創建行對象 , 包含多個 View 的對象
// 步驟二。創建行對象 , 包含多個 View 的對象
class Line {
//2.1 創建存儲 View 的集合
public List mViews = new ArrayList();
//2.2 添加元素
//2.3 獲取行的高度 : 行裏面最高的一個控件的高度 .( 只有元素最高值 設置下,所有元素才能存放 )
public int getLineHeight() {
int height = 0;
for (View view : mViews) {
//2.4 遍歷取得最大高度 賦值給 height
view.measure(0, 0);
height = Math.max(height, view.getMeasuredHeight());
}
return height;
}
//2.5. 行內所有元素的寬度 ( 只有把元素的寬度進行累加 )
public int getAllViewWidth() {
int width = 0;
//2.6. 累加
for (View view : mViews) {
//2.7. 遍歷
view.measure(0, 0);
width += view.getMeasuredWidth();
}
return width;
}
}

`
步驟三。將所有的子元素裝進行裏面,如果滿一行就得換行繼承裝
private int vSpace = 6;
private int hSpace = 6;
// 步驟三。將所有的子元素裝進行裏面,如果滿一行就得換行繼承裝
3.1. 創建構造流式佈局的行的集合
private List mLines = new ArrayList<>();
//3.3. 創建第一行
if (mLines.size() == 0) {
curr = new Line();
//3.4. 第一行是屬於行集合的
mLines.add(curr);
//3.5. 添加進行第一行的第一個元素進行
curr.mViews.add(child);
} else {
//3.6. 從第二個元素起,餘下空間 >= 需要空間 , 可以存放
// 需要空間 = 間隔 + 元素寬度
// 餘下空間 = 總寬度 - 所有元素的寬度和 -(n-1)*hSpace
int needSpace = hSpace + cWidth;
// MeasureSpec.getSize 將測量值轉換成像素值
int layoutWidth = MeasureSpec.getSize(widthMeasureSpec);
int remainSpace = layoutWidth - curr.getAllViewWidth() - (curr.mViews.size() - 1) * hSpace;
if (remainSpace >= needSpace) {
curr.mViews.add(child);
}
//3.7. 餘下空間 < 需要空間 , 換行 ( 創建一個新行 )
else {
//3.8 創建一個新行
curr = new Line();
//3.9, 行是屬性於集合的
mLines.add(curr);
//3.10. 往當前行裏面添加元素
curr.mViews.add(child);
}
}
步驟四 . 計算出流式佈局需要的寬高
// 步驟四 . 計算出流式佈局需要的寬高
//4.1 通過 onMeasure 提供的 widthMeasureSpec 測量值 ,再通過 MeasureSpec 的 getSize 獲取像素 480
layoutWidth = MeasureSpec.getSize(widthMeasureSpec);
//4.2. 流式佈局的高度 跟行數相關,行數越大,高度越大。流式佈局高度 = 所有行的高度和 + ( n-1 ) *vSpace
layoutHeight = 0;
//4.2.1 所有行的高度和
for (int i = 0; i < mLines.size(); i++) {
Line line = mLines.get(i);
layoutHeight += line.getLineHeight();
}
//4.2.2. ( n-1 ) *vSpace
layoutHeight = layoutHeight + (mLines.size() - 1) * vSpace;
//4.3 設置佈局的寬高 參數 1. 寬 , 參數 高
setMeasuredDimension(layoutWidth, layoutHeight);//
}
步驟五。擺放分好行的每個元素 layout(left,top,right,bottom)
// 步驟五。擺放分好行的每個元素 layout(left,top,right,bottom)
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//5.1. 遍歷每一行
for (int i = 0; i < mLines.size(); i++) {
Line line = mLines.get(i);
//5.4 獲取當前行的 top
int lineTop = getCurrLineTop(i);
//5.2. 遍歷行中的所有元素
for (int j = 0; j < line.mViews.size(); j++) {
View view = line.mViews.get(j);
//5.3 設置元素的 left,top,right bottom
int left = 0;
if (j == 0) {
// 本行中的第一個元素的座標 0,0
left = 0;
} else// 非第一個元素
{
// 第二個元素起的 left 值爲前一個元素的 right 加上水平間隔
left = line.mViews.get(j - 1).getRight() + hSpace;
}
int top = lineTop;
// 寬度 =right-left 高度 = bottom-top
//5.5 將不能使用的空間均分給每個控件,增加它們的寬度
//5.5.1 獲取每個元素分配的空間
int eachSpace=getEachSpace(line);
//5.5.2. 分配給每個控件的 right
int right = left + view.getMeasuredWidth()+eachSpace;
int bottom = top + view.getMeasuredHeight();
view.layout(left, top, right, bottom);
//5.5.3. 處理內容居中顯示
//MeasureSpec.EXACTLY 100dp
int newWidth=view.getMeasuredWidth()+eachSpace;
int newMeasureWidth=MeasureSpec.makeMeasureSpec(newWidth,MeasureSpec.EXACTLY);
view.measure(newMeasureWidth,MeasureSpec.UNSPECIFIED);//–>onDraw
}
}
}
private int getEachSpace(Line line) {
// 獲取餘下不可用空間
int remainUnusedSpace=layoutWidth-line.getAllViewWidth()-(line.mViews.size()-1)*hSpace;
// 除以元素個數 3/5 0.6
return (int) (remainUnusedSpace*1f/line.mViews.size());
}
private int getCurrLineTop(int curr) {//
int top = 0;
for (int i = 0; i < curr; i++) {
Line line = mLines.get(i);
// 累加
top += (line.getLineHeight() + vSpace);
}
return top;
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章