自定義view之流式佈局
阿新 • • 發佈:2018-12-14
如圖:
自定義view 繼承viewgroup 實現流式佈局
(程式碼中有註釋,就不一一詳解了,注意標紅欄位)
public class WaterfallViewGroup extends ViewGroup { //儲存所有子View private List<List<View>> mAllChildViews = new ArrayList<>(); //每一行的高度 private List<Integer> mLineHeight = new ArrayList<>(); public WaterfallViewGroup(Context context) { this
(context, null); } public WaterfallViewGroup(Context context, AttributeSet attrs) { this(context, attrs, -1); } public WaterfallViewGroup(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 測量view的尺寸 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //父控制元件傳進來的寬度和高度以及對應的測量模式 int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); //如果當前ViewGroup的寬高為wrap_content的情況 int width = 0;//自己測量的 寬度 int height = 0;//自己測量的高度 //記錄每一行的寬度和高度 int lineWidth = 0; int lineHeight = 0; //獲取子view的個數 int childCount = getChildCount(); for(int i = 0;i < childCount; i ++){ View child = getChildAt(i); //測量子View的寬和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); //得到LayoutParams MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); //子View佔據的寬度 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; //子View佔據的高度 int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; //換行時候 if(lineWidth + childWidth > sizeWidth){ //對比得到最大的寬度 width = Math.max(width, lineWidth); //重置lineWidth lineWidth = childWidth; //記錄行高 height += lineHeight; lineHeight = childHeight; }else{//不換行情況 //疊加行寬 lineWidth += childWidth; //得到最大行高 lineHeight = Math.max(lineHeight, childHeight); } //處理最後一個子View的情況 if(i == childCount -1){ width = Math.max(width, lineWidth); height += lineHeight; } } //wrap_content setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width, modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub mAllChildViews.clear(); mLineHeight.clear(); //獲取當前ViewGroup的寬度 int width = getWidth(); int lineWidth = 0; int lineHeight = 0; //記錄當前行的view List<View> lineViews = new ArrayList<View>(); int childCount = getChildCount(); for(int i = 0;i < childCount; i ++){ View child = getChildAt(i); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); //如果需要換行 if(childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width){ //記錄LineHeight mLineHeight.add(lineHeight); //記錄當前行的Views mAllChildViews.add(lineViews); //重置行的寬高 lineWidth = 0; lineHeight = childHeight + lp.topMargin + lp.bottomMargin; //重置view的集合 lineViews = new ArrayList(); } lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin); lineViews.add(child); } //處理最後一行 mLineHeight.add(lineHeight); mAllChildViews.add(lineViews); //設定子View的位置 int left = 0; int top = 0; //獲取行數 int lineCount = mAllChildViews.size(); for(int i = 0; i < lineCount; i ++){ //當前行的views和高度 lineViews = mAllChildViews.get(i); lineHeight = mLineHeight.get(i); for(int j = 0; j < lineViews.size(); j ++){ View child = lineViews.get(j); //判斷是否顯示 if(child.getVisibility() == View.GONE){ continue; } MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int cLeft = left + lp.leftMargin; int cTop = top + lp.topMargin; int cRight = cLeft + child.getMeasuredWidth(); int cBottom = cTop + child.getMeasuredHeight(); //進行子View進行佈局 child.layout(cLeft, cTop, cRight, cBottom); left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = 0; top += lineHeight; } } /** * 與當前ViewGroup對應的LayoutParams */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { // TODO Auto-generated method stub return new MarginLayoutParams(getContext(), attrs); } }
在MainActivity裡建立集合,把資料傳進去,設定控制元件的樣式、顔色等……
public class MainActivity extends AppCompatActivity {
private String mNames[] = {
"welcome","android","TextView",
"apple","jamy","kobe bryant",
"jordan","layout","viewgroup",
"margin","padding","text",
"name","type","search","logcat","我們在生命中行走,看不同的風景,遭遇不同的陌生人。有些人只是遇見,匆匆的行程裡眼光的一次對視。有些人會在心上駐留一些時間,帶給彼此溫暖。那是最美的一種際遇,留待餘生去不斷重複地去想起……",
"做人凡事要靜、靜靜的來、靜靜的去、切忌喧譁。","要想贏,就一定不能怕輸。不怕輸,結果未必能贏。但是怕輸,結果則一定是輸。"
};
private WaterfallViewGroup flowLayout;//注意:這個是你當前的自定義控制元件!!!
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initChildViews();
}
private void initChildViews() {
// TODO Auto-generated method stub
flowLayout = findViewById(R.id.flow_layout);//注意:這個是你當前的自定義控的id
ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.leftMargin = 5;
lp.rightMargin = 5;
lp.topMargin = 5;
lp.bottomMargin = 5;
for(int i = 0; i < mNames.length; i ++){
TextView view = new TextView(this);
view.setText(mNames[i]);
view.setTextColor(Color.WHITE);
view.setBackgroundDrawable(getResources().getDrawable(R.drawable.textview_bg));
flowLayout.addView(view,lp);
}
}
}
接下來就是佈局了:在你的drawable檔案下建立一個shape: textview_bg
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#666666" />
<corners android:radius="10dp" />
<padding
android:left="5dp"
android:right="5dp"
android:top="5dp"
android:bottom="5dp"
/>
</shape>
然後再activity_main 佈局中直接引用即可
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.baway.waterfallview.WaterfallViewGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/flow_layout"/>
</android.support.constraint.ConstraintLayout>