[自定义控件]android自定义view基础

[自定义控件]android自定义view基础

尊重原创,转载请注明出处: http://blog.csdn.net/qq137722697

[自定义控件]android自定义view实战之太极图(传送门) ————>这是一篇自定view的实战文章

大部分的自定义view包括以下的步骤:

1、在style.xml文件中定义暴露的属性;

2、继承view或其子类,重写构造方法,获取;

[ 3、重写onMeasure方法,获取/设置控件的大小; ]

4、重写onDraw方法,实际的绘制逻辑。

第三步可以不走哦;

一、资源文件(style.xml)中定义可以暴露的属性

如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="YZMView">
        <attr name="text" format="string" />
        <attr name="textSize" format="dimension" />
        <attr name="textColor" format="color|reference" />
    </declare-styleable>
</resources>

这里的format有下面的值:

1、reference:引用资源ID类型,如android:text=”@string/str_title”,str_title=“标题”;

2、color:颜色类型,如为字体设置颜色;

3、boolean:布尔类型,如设置是否显示;

4、dimension:尺寸大小类型,如设置字体的大小;

5、float:浮点类型,如设置透明度;

6、integer:整形类型,如设置时间间隔;

7、string:字符串类型,如设置字体内容;

8、fraction:百分数类型,如设置点的相对位置;

9、enum:枚举类型,如某个属性只能有几个固定的值;

10、flag:位或运算类型,如属性多选。

温馨提示:一个属性值可以设置多种类型。

二、继承view或其子类,重写构造方法,获取属性

在有三个参数的构造方法中使用TypedArray(属性类型数组来获取),TypedArray需要关联布局文件中的属性:attrs,defStyle为构造方法中的参数,直接使用即可,这里只需要传入自动一的属性资源R.styleable.YZMView

TypedArray arr=context.getTheme().obtainSyteleAttributes(attrs,R.styleable.YZMView,defStyle,0);

上面是映射属性,属性是需要拿来设置,如何拿呢?其实它已经存在TypedArray了

public class YZMView extends View {
    private String text = "1234";
    private float textSize = 48;
    private int textColor = 0xFFFFFFFF;   

    public YZMView(Context context) {
        this(context, null);
    }

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

    public YZMView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.YZMView, defStyleAttr, 0);
        textSize = ta.getDimension(R.styleable.YZMView_textSize, 48);//16sp=48px默认16sp
        textColor = ta.getColor(R.styleable.YZMView_textColor, 0xFFFFFFFF);
        ta.recycle();//及时释放        
    }
  }

三、重写onMeasure方法,获取/设置控件的大小

以下基本上是固定写法(当然有些view是不需要重写这个方法的):

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);//获取宽的模式
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);//获取宽的值
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);//获取高的模式
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);//获取高的值
        if (widthMode == MeasureSpec.AT_MOST) {//如果用户设置了宽度为wrap_content,那么就要自己测量了
            widthSize =200;//设置默认值
        }
        if (heightMode == MeasureSpec.AT_MOST) {//如果用户设置高度为wrap_content,也是要自己测量
            heightSize =100;//设置默认值
        }
        setMeasuredDimension(widthSize, heightSize);//设置测量的宽度
    }

测量大小的类型:

EXACTLY:设置了明确的值或者match_parent

AT_MOST:设置为warp_content

UNSPECLIFIED:想多大就多大,一般不用

如果使用自定义控件的地方使用了wrap_content,那么系统是默认的是测量全部,这里需要自己处理一下(就像上面的固定写法一样)

四、重写onDraw方法,实际的绘制逻辑

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);//这里需要调用父类的绘制方法,这样系统会为本view绘制一些基本通用属性,如背景颜色
        canvas.drawText(text, getMeasuredWidth() / 2 - mRect.width() / 2, getMeasuredHeight() / 2 + mRect.height() / 2, mPaint);
    }

Paint画笔对象

android中画笔工具叫Paint,它可以画任何几何图形、文字、bitmap、setAnitAlias(true)表示去掉齿轮。

Paint的Style有3种:

Paint.Style.FILL 填充内部

Paint.Style.FILL_AND_STROKE 填充内部和描边

Paint.Style.STROKE 描边

这里写图片描述

Paint详细介绍

http://blog.csdn.net/abcdef314159/article/details/51720686

关于重绘

控件重绘就是重新调用“onDraw()”【原理就是,使用view.postInvalidate()——>子线程中使用,view.invalidate()——>主线程中调用】方法触发onDraw()。

五、实例

下面用一个简单验证码的实例来进入自定义view

这里写图片描述

属性定义(res/style.xml):

<resources>
    <declare-styleable name="YZMView">
        <attr name="text" format="string|reference" />
        <attr name="textSize" format="dimension" />
        <attr name="textColor" format="color|reference" />
    </declare-styleable>    
</resources>

YZMView类:

/**
 * 自定义View-------验证码
 * Created by HDL on 2017/2/5.
 */

public class YZMView extends View {
    private String text = "1234";
    private float textSize = 48;
    private int textColor = 0xFFFFFFFF;
    private Paint mPaint;
    private Rect mRect;
    private static final String TAG = "YZMView";

    public YZMView(Context context) {
        this(context, null);
    }

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

    public YZMView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        createCode();
        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.YZMView, defStyleAttr, 0);
        textSize = ta.getDimension(R.styleable.YZMView_textSize, 48);
        textColor = ta.getColor(R.styleable.YZMView_textColor, 0xFFFFFFFF);
        ta.recycle();//及时释放
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                createCode();
                Log.e(TAG, "setOnClickListener: " + text);
                postInvalidate();
            }
        });

        mPaint = new Paint();
        mPaint.setAntiAlias(true);//取消锯齿
        mPaint.setTextSize(textSize);
        Log.e(TAG, "YZMView: " + textColor);
        mPaint.setColor(textColor);
        mRect = new Rect();
        mPaint.getTextBounds(text, 0, text.length(), mRect);//将text的边框赋值给mrect
    }

    /**
     * 随机创建4位数字
     */
    private void createCode() {
        text = "";
        for (int i = 0; i < 4; i++) {
            text += (int) (Math.random() * 10 - 1) + "";
        }
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText(text, getMeasuredWidth() / 2 - mRect.width() / 2 - 6.6f, getMeasuredHeight() / 2 + mRect.height() / 2, mPaint);//加6.6是因为有测量误差
    }
}

在布局文件中使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="view.cusstom.hdl.com.customview.MainActivity">

    <view.cusstom.hdl.com.customview.YZMView
        android:id="@+id/yzm_main_code"
        android:layout_width="80dp"
        android:layout_height="40dp"
        android:background="#c9c7c9"
        app:textColor="#090a09"
        app:textSize="30sp" />
    <Button
        android:layout_width="wrap_content"
        android:text="校验"
        android:onClick="onCheck"
        android:layout_height="wrap_content" />
</LinearLayout>

添加噪点的代码就很简单了,for循环画指定数量的点和线即可,这里就不贴了,网上一大堆。

觉得不错的话顶一个吧

尊重原创,转载请注明出处: http://blog.csdn.net/qq137722697

发布了60 篇原创文章 · 获赞 252 · 访问量 43万+

猜你喜欢

转载自blog.csdn.net/qq137722697/article/details/54883962