Android初级自定义View和ViewGroup

MyView继承View:

/**
 * Created by zhaochengfang on 2020/12/8
 */
public class MyView extends View {

    private int defaultSize;

    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //第二个参数就是我们在styles.xml文件中的<declare-styleable>标签
        //即属性集合的标签,在R文件中名称为R.styleable + name
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyView);

        //第一个参数为属性集合里边的属性,R文件名称:R.styleable + 属性集合名称 + 下划线 + 属性名称
        //第二个参数为,如果没有设置这个属性,则设置的默认的值
        defaultSize = array.getDimensionPixelSize(R.styleable.MyView_default_size,200);

        //将TypedArray对象回收
        array.recycle();
    }

    private int getMySize(int defaultSize,int measureSpec){

        int mySize = defaultSize;

        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        switch (mode){
            //父容器没有对当前View有任何限制,当前View可以任意取尺寸,如果没有指定大小,就设置为默认大小
            case MeasureSpec.UNSPECIFIED:{
                mySize = defaultSize;
                break;
            }
            //wrap_content,当前尺寸是当前View能取的最大尺寸,如果测量模式是最大取值为size,我们将大小取最大值,你也可以取其他值
            case MeasureSpec.AT_MOST:
            //match_parent||固定尺寸(如100dp),当前的尺寸就是当前View应该取的尺寸,如果是固定的大小,那就不要去改变它
            case MeasureSpec.EXACTLY: {
                mySize = size;
                break;
            }
            default:
                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);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int r = getMeasuredWidth() / 2;
        int centerX =  r;
        int centerY =  r;

        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        //开始绘制
        canvas.drawCircle(centerX,centerY,r,paint);
    }
}

MyViewGroup继承ViewGroup:

/**
 * Created by zhaochengfang on 2020/12/8
 */
public class MyViewGroup extends ViewGroup {


    public MyViewGroup(Context context) {
        super(context);
    }

    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //将所有的子View进行测量,这会触发每个子View的onMeasure函数
        //注意要与measureChild区分,measureChild是对单个View进行测量
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int childCount = getChildCount();

        if (childCount == 0){//如果没有子View,当前ViewGroup没有存在的意义,不用占用空间
            setMeasuredDimension(0,0);
        }else {
            //如果宽高都是包裹内容
            if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
                //我们将高度设置为所有子View的高度相加,宽度设置为子View中的最大的宽度
                int height = getTotalHeight();
                int width = getMaxChildWidth();
                setMeasuredDimension(width,height);
            }else if (heightMode == MeasureSpec.AT_MOST){//如果只有高度是包裹内容
                //宽度设置为ViewGroup自己的测量宽度高度设置为所有子View的高度总和
                setMeasuredDimension(widthSize,getTotalHeight());
            }else if (widthMode == MeasureSpec.AT_MOST){//如果只有宽度是包裹内容
                //宽度设置为子View中宽度最大的值,高度设置为ViewGroup自己的测量值
                setMeasuredDimension(getMaxChildWidth(),heightSize);
            }
        }


    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int count = getChildCount();
        //记录当前的高度位置
        int curHeight = 0;
        //将子View逐个摆放
        for (int i = 0; i < count; i ++){
            View child = getChildAt(i);
            int height = child.getMeasuredHeight();
            int width = child.getMeasuredWidth();
            //摆放子View,参数分别是子View矩形区域的左、上、右、下边
            child.layout(0,curHeight,0 + width,curHeight + height);
            curHeight += 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 getTotalHeight(){
        int childCount = getChildCount();
        int height = 0;
        for (int i = 0; i < childCount; i ++){
            View childView = getChildAt(i);
            height += childView.getMeasuredHeight();
        }

        return height;
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:zcf="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"
    android:orientation="vertical"
    >

    <com.android.view.MyView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        zcf:default_size="200dp"
        />
    <com.android.view.MyView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        zcf:default_size="200dp"
        />
    <com.android.view.MyViewGroup
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff9900"
        >

        <Button
            android:layout_width="100dp"
            android:layout_height="30dp"/>
        <Button
            android:layout_width="100dp"
            android:layout_height="200dp"/>
        <Button
            android:layout_width="100dp"
            android:layout_height="50dp"/>
        <Button
            android:layout_width="100dp"
            android:layout_height="100dp"/>

    </com.android.view.MyViewGroup>

</LinearLayout>

效果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值