1. 程式人生 > >imooc學習筆記——流式佈局和熱門標籤

imooc學習筆記——流式佈局和熱門標籤

在看imooc打造Android中的流式佈局和熱門標籤這個課程時,感覺沒有什麼太大難度,但是一練習就發現有很多問題會不斷出現,於是就有了這個筆記…..

個人筆記,個人理解 , 如有錯誤歡迎指正

要想實現流式佈局 Android中沒有現成的控制元件,所以需要我們自己寫,也就傳說中的自定義View啦!

對自定義View的瞭解不是很多, 目前我的理解是

1、 繼承View或者ViewGroup (或者其子類)
2、 根據需要重寫其方法
3、 使用

其實這三點就是廢話。。。。但也的確就是這樣的=.=

繼承

流式佈局 應該都見過,它是要放控制元件的容器,所以不能繼承View 必須繼承ViewGroup或其子類


視訊中繼承的是ViewGroup 至於為什麼不繼承RelativeLayout、LinearLayout、FrameLayout 我也沒有想太明白。。。。

繼承後必須實現protected void onLayout(boolean changed, int l, int t, int r, int b) {} 和 幾個構造器

onLayout 這個方法是設定子view的位置 ,那麼設定位置的前提 是要知道要設定子view的大小吧
那麼需要用到onMeasure方法, 這個是測量子View和自身的寬高
如果想要知道子View的一些引數那麼得需要 子view.getLayoutParams

這個方法,返回型別的是ViewGroup.LayoutParams
我們可能會需要子View的margin,然而能獲取子ViewMargin 的是ViewGroup.MarginLayoutParams這個類,
所以我們子view的父容器(也就是我們自定義的ViewGroup)必須返回子View一個ViewGroup.MarginLayoutParams型別的LayoutParams,怎麼返回呢
這個方法是在public LayoutParams generateLayoutParams(AttributeSet attrs) {}中返回的

OK,繼承如下

public class
MyGroupView extends ViewGroup {
public MyGroupView(Context context) { this(context, null); } public MyGroupView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyGroupView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec,heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return super.generateLayoutParams(attrs); } }

重寫

1、重寫generateLayoutParams,讓其返回MarginLayoutParams型別,這樣子View才可獲取Margin

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

2、重寫onMeasure,這樣才可以知道ViewGroup應該繪製多大

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width_size = MeasureSpec.getSize(widthMeasureSpec);
        int height_size = MeasureSpec.getSize(heightMeasureSpec);
        int width_mode = MeasureSpec.getMode(widthMeasureSpec);
        int height_mode = MeasureSpec.getMode(heightMeasureSpec);
        int width = 0, height = 0, line_width = 0, line_height = 0;
        int mCount = getChildCount();
        int viewWidth = 0, viewHeight = 0;
        //遍歷ChildView 獲得 width 和height
        for (int i = 0; i < mCount; i++) {
            View view = getChildAt(i);
            measureChild(view, widthMeasureSpec, heightMeasureSpec);
            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();

            viewWidth = params.leftMargin + params.rightMargin + view.getMeasuredWidth();
            viewHeight = params.topMargin + params.bottomMargin + view.getMeasuredHeight();

            if (line_width + viewWidth > width_size - getPaddingRight() - getPaddingLeft()) {//換行
                width = Math.max(width, line_width);//寬度為最寬的行寬
                height += line_height;//高度累加

                //清除以前的寬高
                line_width = viewWidth ;
                line_height = viewHeight;
            } else {//無需換行
                line_width += viewWidth;//累加
                line_height = Math.max(line_height, viewHeight);//高度為最高的行高
            }

            if (i == mCount - 1) {//最後一個控制元件
                width = Math.max(width, line_width);//寬度為最寬的行寬
                height += line_height;//高度累加
            }

        }

        setMeasuredDimension(//如果是EXACTLY設定原來大小,如果不是則設定計算後的大小
                width_mode == MeasureSpec.EXACTLY ? width_size : width + getPaddingRight() + getPaddingLeft(),//
                height_mode == MeasureSpec.EXACTLY ? height_size : height + getPaddingTop() + getPaddingBottom()//
        );

    }

3、重寫onLayout,開始分配每個子View的位置

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int line_width = getPaddingLeft(), line_height = 0;
        int mCount = getChildCount();
        int left = 0, top = getPaddingTop();

        //遍歷ChildView 
        for (int i = 0; i < mCount; i++) {
            View view = getChildAt(i);
        //獲得子View屬性
            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
            int viewWidth = params.leftMargin + params.rightMargin + view.getMeasuredWidth();
            int viewHeight = params.topMargin + params.bottomMargin + view.getMeasuredHeight();

            if (line_width + viewWidth > getWidth() - getPaddingLeft()) {//換行
                left = getPaddingLeft();
                top += line_height;//高度累加
                view.layout(left + params.leftMargin, top + params.topMargin,
                        left + view.getMeasuredWidth() + params.rightMargin,
                        top + view.getMeasuredHeight() + params.bottomMargin);

                //清除寬高
                line_width = viewWidth + getPaddingLeft();
                line_height = viewHeight;

            } else {//無需換行
                left = line_width;
        //為
                view.layout(left + params.leftMargin, top + params.topMargin,
                        left + view.getMeasuredWidth() + params.rightMargin,
                        top + view.getMeasuredHeight() + params.bottomMargin);

                line_width += viewWidth;//累加行寬
                line_height = Math.max(line_height, viewHeight);//高度為最高的控制元件高度
            }
        }
    }

使用

使用方法很簡單啦

就是在佈局檔案中新增進去就好了
<包名.自定義ViewGroup名>

比如我的就是這樣
這裡寫圖片描述

   <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <sunshine.myview.MyGroupView
        android:id="@+id/view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#f00"
        android:padding="20dp">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New Button" />
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ccc">
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:background="#ca0"
                android:text="New Button" />
        </LinearLayout>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111aa1a11111" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ccc"
            android:gravity="center"
            android:padding="10dp"
            android:text="aaaaaaaa" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="NNNNNNNNNNNNssssNNNNaaaaaaaaaaaaaaaaNNNaaaa" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="New Button" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Neon" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#cc0"
            android:gravity="center"
            android:padding="10dp"
            android:text="aaaa" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ccc"
            android:gravity="center"
            android:padding="10dp"
            android:text="aaaaaaaaaaaaaaaaaaaaassaaaaassddddaa" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New Button" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New Button" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="NBonssss" />
    </sunshine.myview.MyGroupView>
</LinearLayout>

少年,加油吧!