自定义View 一 (继承VIew重写onDraw方法)

项目:具有圆形效果的自定义View

一、继承View并重写onDraw方法

public class CircleView extends View{
    private static final int COLOR = Color.RED;
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mWidth = 0;
    private int mHeight = 0;

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

    public CircleView(Context context) {
        super(context);
        init();
    }

    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPaint.setColor(COLOR);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取当前View的宽/高
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
        //获取半径
        int radium = Math.min(mWidth,mHeight)/2;
        //画圆
        canvas.drawCircle(mWidth/2,mHeight/2,radium,mPaint);
    }

}
CircleView

在xml中测试margin发现可以用,说明margin是由父容器控制的(想起measureChildMarginLayout源码)

但是wrap_content和padding都不生效。

二、让wrap_content生效

根据上一章View的工作原理:①、重写onMeasure方法  ②、给CircleView设定一个固定的宽高

//设定wrap_content时候的宽度    
private static final int AT_WIDTH = 30;
private static final int AT_HEIGHT = 30;

//重写onMeasure()方法
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取子View的范围
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
       //判断当属性为wrap_content的时候
        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(AT_WIDTH,AT_HEIGHT);
        }
        else if (widthMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(AT_WIDTH,heightSize);
        }
        else if (heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSize,AT_HEIGHT);
        }
        else {
            super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        }
    }    

三、解决无法padding的问题

原理:只需要在onDraw中,获取padding的参数就可以了

//重写onDraw方法
 protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取padding
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        //获取当前View的宽/高 减去padding
        mWidth = getMeasuredWidth() - paddingLeft - paddingRight;
        mHeight = getMeasuredHeight() - paddingTop - paddingBottom;
        //获取半径
        int radium = Math.min(mWidth,mHeight)/2;
        //画圆
        canvas.drawCircle(paddingLeft+mWidth/2,paddingTop - mHeight/2,radium,mPaint);
    }
CircleView

四、自定义属性

步骤:①、在values目录中创建xml文件名,文件名必须以attr_开头。②、内容的编写:<declare-styleadable>标签中:name代表自定义属性(该为CircleView类) 

<attr>标签中 name代表之后使用的属性名(circle_color),format代表格式(color)

<resources>
    <declare-styleable name="CircleView">
        <attr name="color_circle" format="color"/>
    </declare-styleable>
</resources>
attr_circleview

步骤③、在布局文件中使用自定义属性  必须在schemas声明:xmlns:app="http://schemas.android.com/apk/res-auto" 其中app名字可以随便替换。

但是circleView中自定义属性名的前缀必须是和这里一致(一般习惯使用app)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    //这一段必须要加    app名字可以替换
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="com.maikefengchao.circleview.MainActivity"> <com.maikefengchao.circleview.CircleView android:layout_width="80dp" android:layout_height="80dp"
//前缀与添加的声明前缀一致
app:color_circle="#9999"/> </LinearLayout>

步骤④:在CircleView中获取自定义属性参数

//在构造方法中使用 
 public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //加载自定义属性集合CircleView
        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CircleView);
        //解析集合中的circle_circle,设置默认颜色
        mColor = a.getColor(R.styleable.CircleView_color_circle,Color.RED);
        init();
    }

全部代码:(P209 ①)

原文地址:https://www.cnblogs.com/rookiechen/p/5427062.html