首页 > 系统 > Android > 正文

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

2019-11-09 18:12:17
字体:
来源:转载
供稿:网友

[自定义控件]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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表