自定义view(再回首)

前几天写的demo没法自己实现在xml声明使用,而是把radius之类的写死了。这样很不方便。

于是继续改进。 栋哥推荐的书的作者,刚神 果然非常厉害。

首先 需要对ondraw方法重写一下。

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        int width = getWidth()-paddingLeft-paddingRight;
        int height = getHeight()-paddingTop-paddingTop;
        int radius = Math.min(width,height)/2;
        // 绘制圆环
        canvas.drawCircle(width/2, height/2, radius, mPaint);


}

这样就可以完成自定义长宽高了,并且半径自动适应。

其实这时候我们还可以进一步完善,给他们提供attr 就是我们自定义的属性。什么是自定义的属性?比如我们用android:layout_width,其实就是android系统给我们提供的。注意 ,如果我们要使用自定义属性 请在布局代码中加入;

xmlns:app="http://schemas.android.com/apk/res-auto"

例如:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
 >


这里的xmlns:android=“http://schemas.android.com/apk/res/android” 就是自动扫描android给我们提供的默认属性。

第一步 在values目录下 创建xml文件,记住要以attrs开头

<?xml version="1.0" encoding="utf-8" ?>
<resources>
    <declare-styleable name="CustomView">
     <!--->attr name是我们自己定义的名字,format是android给我们提供的格式 可以搜一下<!-->
        <attr name="circle_color" format="color"></attr>
        <!--->照虎画🐱  自己定一个属性试一下<!-->
        <attr name="circle_style" format="float"></attr>
    </declare-styleable>


</resources>

这样就ok的设置了自定义的属性。

接下来就是我们view控件里的操作了,比如这里。先声明;

    private int mColor  ;
    private float mStrokeWidth;

接着我们就要取出在布局中定义的属性,若没有定义,我们应该默认一个。

    public CustomView(Context context,AttributeSet attrs,int defStyleAttr){
        super(context,attrs,defStyleAttr);
        TypedArray  a =context.obtainStyledAttributes(attrs,R.styleable.CustomView);
        mColor = a.getColor(R.styleable.CustomView_circle_color,Color.RED);
        mStrokeWidth = a.getFloat(R.styleable.CustomView_circle_style,20);
        a.recycle();
        initPaint();
    }

ok,基本大功告成,在init的时候对画笔什么的进行相关设置即可。贴上完整的view代码。

package com.example.testviewgroup;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CustomView extends View {
    private Paint mPaint;// 画笔
    private int mColor  ;
    private float mStrokeWidth;

    public CustomView(Context context) {

        this(context, null);
        // 初始化画笔
        initPaint();
    }


    public CustomView(Context context, AttributeSet attrs) {
        this(context, attrs,0);

    }

    public CustomView(Context context,AttributeSet attrs,int defStyleAttr){
        super(context,attrs,defStyleAttr);
        TypedArray  a =context.obtainStyledAttributes(attrs,R.styleable.CustomView);
        mColor = a.getColor(R.styleable.CustomView_circle_color,Color.RED);
        mStrokeWidth = a.getFloat(R.styleable.CustomView_circle_style,20);
        a.recycle();
        initPaint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
       mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        /*
         * 设置画笔样式为描边,圆环嘛……当然不能填充不然就么意思了
         *
         * 画笔样式分三种:
         * 1.Paint.Style.STROKE:描边
         * 2.Paint.Style.FILL_AND_STROKE:描边并填充
         * 3.Paint.Style.FILL:填充
         */

        //描边
        mPaint.setStyle(Paint.Style.STROKE);
        //为画笔设置咱们自己的颜色属性
        mPaint.setColor(mColor);
        mPaint.setStrokeWidth(mStrokeWidth);
        /*
         * 设置描边的粗细,单位:像素px
         * 注意:当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
         */
       // mPaint.setStrokeWidth(mStrokeWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);`在这里插入代码片`
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        int width = getWidth()-paddingLeft-paddingRight;
        int height = getHeight()-paddingTop-paddingTop;
        int radius = Math.min(width,height)/2;
        // 绘制圆环
        canvas.drawCircle(width/2, height/2, radius, mPaint);


}}

我们定义了一个圆环,提供了两个自定义属性,分别是颜色和秒边宽度,若不定义,默认为红色和20.

👌

这个时候问题又来了,根据绘制源码知道,若不对onMeasure加以处理,在对自定义view设置wrap_content时,会等于父控件的大小,就等于math_parent, 显然是不对的。

所以对onMeasure进行重写。

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        if(widthSpecMode ==MeasureSpec.AT_MOST&&heightSpecMode==MeasureSpec.AT_MOST){
            setMeasuredDimension(200,200);
        }
        else if(widthMeasureSpec ==MeasureSpec.AT_MOST){
            setMeasuredDimension(200,heightSpecSize);
        }
        else if(heightSpecMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSpecSize,200);
        }


    }

上述代码是的200是我们默认设置的(AT_MOST下的自定义宽度,关于MeasureSpec,您可以自行搜索,这里推荐一本书《android开发艺术探索》),你也可以自己设置它。

-------------分割线----------------

但是问题又来了,我们要考虑用户使用,这是一个圆。当用户设定宽/高其中一个为 确切的 值,另一个为wrap_content时候,我们显然应该是将其中一个设定的为圆。并且处理一下我们圆的线宽,以免不能完整显示。故再次修改一下,完整代码如下

package com.example.testviewgroup;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CustomView extends View {
    private Paint mPaint;// 画笔
    private int mColor;
    private float mStrokeWidth;

    public CustomView(Context context) {

        this(context, null);
        // 初始化画笔

    }


    public CustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
        mColor = a.getColor(R.styleable.CustomView_circle_color, Color.RED);
        mStrokeWidth = a.getFloat(R.styleable.CustomView_circle_style, 20);
        a.recycle();
        initPaint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(200, 200);
        } else if (widthMeasureSpec == MeasureSpec.AT_MOST) {
            setMeasuredDimension(heightSpecSize, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, widthSpecSize);
        }


    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        /*
         * 设置画笔样式为描边,圆环嘛……当然不能填充不然就么意思了
         *
         * 画笔样式分三种:
         * 1.Paint.Style.STROKE:描边
         * 2.Paint.Style.FILL_AND_STROKE:描边并填充
         * 3.Paint.Style.FILL:填充
         */

        //描边
        mPaint.setStyle(Paint.Style.STROKE);
        //为画笔设置咱们自己的颜色属性
        mPaint.setColor(mColor);
        mPaint.setStrokeWidth(mStrokeWidth);
        /*
         * 设置描边的粗细,单位:像素px
         * 注意:当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
         */
        // mPaint.setStrokeWidth(mStrokeWidth);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        int width = getWidth() - paddingLeft - paddingRight;
        int height = getHeight() - paddingTop - paddingTop;
        int radius = Math.min(width, height) / 2;
        // 绘制圆环
        canvas.drawCircle(width / 2, height / 2, radius - mStrokeWidth, mPaint);


    }


}


然后我们可以提供一些优先级之类的属性,这个自己去做就好了,要搭配自定义的ViewGroup使用。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值