Android 自定義View、ViewGroup和自定義屬性


一、Android自定義view屬性

1.在res/values/styles.xml文件里面聲明一個我們自定義的屬性:

<resources>
    <!--name為聲明的"屬性集合"名,可以隨便取,但是最好是設置為跟我們的View一樣的名稱-->
    <declare-styleable name="CircleView">
        <!--聲明我們的屬性,名稱為default_size,取值類型為尺寸類型(dp,px等)-->
        <attr name="radius" format="dimension"></attr>
        <attr name="circle_color" format="color"></attr>
    </declare-styleable>
</resources>

 

2.在自定義View中獲取對應設置的屬性值
public CircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //即屬性集合的標簽,在R文件中名稱為R.styleable+name
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
        //第一個參數為屬性集合里面的屬性,R文件名稱:R.styleable+屬性集合名稱+下划線+屬性名稱
        //第二個參數為,如果沒有設置這個屬性,則設置的默認的值
        radius = typedArray.getDimensionPixelOffset(R.styleable.CircleView_radius, 20);
        color = typedArray.getColor(R.styleable.CircleView_circle_color, 000000);
        //最后記得將TypedArray對象回收
        typedArray.recycle();
    }

 

3.在xml文件中設置屬性值
(1)首先需要定義命名空間 xmlns:rc="http://schemas.android.com/apk/res-auto"
(2)設置屬性值 rc:radius   rc:circle_color
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:rc="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.ruanchao.todaynews.UserViewActivity">
 
    <com.ruanchao.todaynews.view.CircleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        rc:radius="50dp"
        rc:circle_color="#FF69B4"/>
 
</LinearLayout>

 

二、Android自定義View

 
1.onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
參數中的widthMeasureSpecheightMeasureSpec包含了兩層信息:測量模式和測量尺寸
  (1)測量模式:
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
測量模式 表示意思
UNSPECIFIED 父容器沒有對當前View有任何限制,當前View可以任意取尺寸(match_parent
EXACTLY 當前的尺寸就是當前View應該取的尺寸(xml配置固定值
AT_MOST 當前尺寸是當前View能取的最大尺寸(wrap_content
(2)尺寸大小:
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
示例代碼:
 
private int getMySize(int defaultSize, int measureSpec) {
        int mySize = defaultSize;
 
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
 
        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果沒有指定大小,就設置為默認大小
                mySize = defaultSize;
                break;
            }
            case MeasureSpec.AT_MOST: {//如果測量模式是最大取值為size
                //我們將大小取最大值,你也可以取其他值
                mySize = size;
                break;
            }
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改變它
                mySize = size;
                break;
            }
        }
        return mySize;
}
 
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMySize(100, widthMeasureSpec);
        int height = getMySize(100, heightMeasureSpec);
 
        if (width < height) {
            height = width;
        } else {
            width = height;
        }
 
        setMeasuredDimension(width, height);
}
<com.hc.studyview.MyView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#ff0000" />
 
2.onDraw 直接在畫板Canvas對象上繪制
(1)invalidate方法會執行onDraw過程,只能在UI線程調用
(2)postInvalidate 可以在非UI線程調用,省去了Handler消息調用
(3)RequestLayout 會執行onMeasure,onLayout ,onDraw

三、Android自定義ViewGroup

自定義ViewGruup要經歷以下幾步:
1、根據各個子View的大小,確定ViewGroup大小(重寫onMeasure()方法)
2、在ViewGroup中進行View的擺放(重寫onLayout()方法)
 
示例代碼:自定義ViewGroup實現LinearLayout布局
第一步:確定ViewGroup大小
 
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int with = MeasureSpec.getSize(widthMeasureSpec);
        int height =  MeasureSpec.getSize(heightMeasureSpec);
        int withMode = MeasureSpec.getMode(widthMeasureSpec);
        int heigthMode = MeasureSpec.getMode(heightMeasureSpec);
        if (getChildCount() == 0) {//如果沒有子View,當前ViewGroup沒有存在的意義,不用占用空間
            setMeasuredDimension(0, 0);
            return;
        }
        if (withMode == MeasureSpec.AT_MOST && heigthMode == MeasureSpec.AT_MOST){
            //高度累加,寬度取最大
            setMeasuredDimension(getMaxChildWidth(),getTotleHeight());
        }else if (heigthMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(with,getTotleHeight());
        }else if (withMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(getMaxChildWidth(),height);
        }
    }
 
    /***
     * 獲取子View中寬度最大的值
     */
    private int getMaxChildWidth() {
        int childCount = getChildCount();
        int maxWidth = 0;
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            if (childView.getMeasuredWidth() > maxWidth) {
                maxWidth = childView.getMeasuredWidth();
            }
        }
        return maxWidth;
    }
 
    /***
     * 將所有子View的高度相加
     **/
    private int getTotleHeight() {
        int childCount = getChildCount();
        int height = 0;
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            height += childView.getMeasuredHeight();
        }
        return height;
    }

 

第二步:在ViewGroup中進行子View的擺放

 @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int count = getChildCount();
        int currentHeigth = 0;
        //將子View逐個擺放
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            int childHeigth = child.getMeasuredHeight();
            child.layout(left, currentHeigth, right + child.getMeasuredWidth(), currentHeigth + childHeigth);
            currentHeigth += childHeigth;
        }
 
    }
測試xml
<com.rc.studyview.MyViewGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ff9900">
 
        <Button
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="btn" />
 
        <Button
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="btn" />
 
        <Button
            android:layout_width="50dp"
            android:layout_height="wrap_content"
 
 
            android:text="btn" />
 
    </com.rc.studyview.MyViewGroup>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM