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