1. 程式人生 > >自定義view之流式佈局

自定義view之流式佈局

如圖:

自定義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>