Android自定义View是Android开发者进阶的必经之路,而对初学者来说说又是非常陌生和惧怕的,所以整理一下自己学习自定义View的一些经验。首先是步骤:
1. 自定义View的属性
2. 获取自定义View属性
3. 重写onMeasure
4. 重新onDraw
其中自定义View的属性是为了让自定义的view能够在UI编辑器中使用并预览,而第二步则是未了让自定义的属性生效,第三步的onMeasure是用来测量View的大小,其中还有onLayout方法用于确定View的位置,这两个方法可以根据需求选择性的重写,而onDraw方法则是必须重写的了,因为我们要在该方法中进行View的绘制工作。
一. 首先我们在res/value目录下新建xml文件并命名为attrs,接下来再改文件中定义自定义View的属性
<resources>
<attrname="titleText"format="string"></attr>
<attrname="titleColor"format="color"></attr>
<attrname="titleSize"format="dimension"></attr>
<declare-styleablename="CustomTextView">
<attrname="titleText"/>
<attrname="titleColor"/>
<attrname="titleSize"/>
</declare-styleable>
<resources>
这里我们定义了文字、文字颜色,文字大小三个属性,其中format的取值范围有:
reference 资源类型,通常是@开头,例如@+id/xxxx,@id/xxxxx
string 字符串类型,通常是文字信息
dimension 浮点类型,通常是尺寸度量,单位有很多px,dp,sp,dip等
color 颜色类型,通常是颜色16进制代码,支持ARGB。
boolean 布尔类型,true和false
enum 枚举类型,通常是代表这个属性提供了几种值来进行选择,并且只能选择这几种中的一个
flag 与enum基本没有区别。
integer 整数类型,通常是整数
二. 接下来我们新建类CustomTextView并继承View。并且在里面做自定义属性的获取,onMeasure的测量以及onDraw的绘制。
@SuppressLint("NewApi")
publicclass CustomTextView extends View {
/**
* 标题
*/
private Stringtitle;
/**
* 标题颜色
*/
privateint titleColor;
/**
* 标题大小
*/
privateint titleSize;
/**
* 绘制时控制文本绘制的范围
*/
RectmRect;
private Paintpaint;
public CustomTextView(Contextcontext, AttributeSet attrs, int defStyleAttr,int defStyleRes) {
super(context,attrs, defStyleAttr,defStyleRes);
init(context,attrs, defStyleAttr,defStyleRes);
}
public CustomTextView(Contextcontext, AttributeSet attrs,int defStyleAttr) {
super(context,attrs, defStyleAttr);
init(context,attrs, defStyleAttr, 0);
}
public CustomTextView(Contextcontext, AttributeSet attrs) {
super(context,attrs);
init(context,attrs, 0, 0);
}
public CustomTextView(Contextcontext) {
super(context);
init(context,null, 0, 0);
}
/**
* 初始化
*
* @param context
* @param attrs
* @param defStyleAttr
* @param defStyleRes
*/
privatevoid init(Context context, AttributeSet attrs, intdefStyleAttr,intdefStyleRes) {
/**
* 获取自定义的属性
*/
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomTextView,defStyleAttr, 0);
intn = typedArray.getIndexCount();
for (inti = 0; i < n; i++) {
intattr = typedArray.getIndex(i);
switch (attr) {
//文字
case R.styleable.CustomTextView_titleText:
title =typedArray.getString(attr);
break;
//文字颜色
case R.styleable.CustomTextView_titleColor:
titleColor =typedArray.getColor(i, Color.BLACK);
break;
//文字大小
case R.styleable.CustomTextView_titleSize:
titleSize =typedArray.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 15,
getResources().getDisplayMetrics()));
break;
default:
break;
}
}
typedArray.recycle();
/**
* 获取要绘制文字的宽高
*/
paint =new Paint();
paint.setTextSize(titleSize);
mRect =new Rect();
paint.getTextBounds(title, 0,title.length(), mRect);
}
/**
* 重写的绘制
*/
@Override
protectedvoid onDraw(Canvas canvas) {
paint.setColor(Color.GREEN);
canvas.drawRect(new Rect(0, 0, getMeasuredWidth(),getMeasuredHeight()),paint);
paint.setColor(titleColor);
canvas.drawText(title, getWidth() / 2 -mRect.width() / 2,
getHeight() / 2 +mRect.height() / 2, paint);
}
/**
* 重写的测量
*/
@Override
protectedvoid onMeasure(intwidthMeasureSpec, intheightMeasureSpec) {
intwidthMode = MeasureSpec.getMode(widthMeasureSpec);
intwidthValue = MeasureSpec.getSize(widthMeasureSpec);
intheightMode = MeasureSpec.getMode(heightMeasureSpec);
intheightValue = MeasureSpec.getSize(heightMeasureSpec);
intwidth, height;
if (widthMode == MeasureSpec.EXACTLY) {
width =widthValue;
} else {
paint.setTextSize(titleSize);
paint.getTextBounds(title, 0,title.length(), mRect);
floattextWidth = mRect.width();
intdesired = (int) (getPaddingLeft() +textWidth+getPaddingRight());
width =desired;
}
if (heightMode == MeasureSpec.EXACTLY) {
height =heightValue;
} else {
paint.setTextSize(titleSize);
paint.getTextBounds(title, 0,title.length(), mRect);
floattextHeight = mRect.height();
intdesired = (int) (getPaddingTop() +textHeight+getPaddingBottom());
height =desired;
}
setMeasuredDimension(width,height);
}
}
三. 到这里为止,自定义TextView的工作已经做完了,接下来就是使用了。这里需要注意的是要使用我们自定义的属性需要引入我们自定义的命名空间即
xmlns:custom="http://schemas.android.com/apk/res/com.fxx.customview"其中的命名空间的名字custom我们可以随便取,而后面的包路径是我们项目的包路径
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.fxx.customview"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.fxx.customview.MainActivity">
<com.fxx.customview.widget.CustomTextView
android:id="@+id/ctv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:titleColor="#ffffff"
custom:titleSize="25sp"
custom:titleText="CustomTextView"/>
</LinearLayout>
四. 接下我们运行项目来看下效果,如图: