自定义View对于很多新手来说都是谈之色变,当然我也不例外,但是在某些情况下需要更加炫酷的效果,更加人性化的体验还是不得不自己去撸一些特定的View出来。自定义View是我们进阶路上的拦路虎,更是我们进阶必备的技能之一。本文主要是记录自身的学习,同时指导新手的学习,高手请避让撸代码去。。。
本文就从自定义最基础的部分开始聊起。
自定义View包含的主要内容如下:
1)自定义属性。
2)测量(onMeasure)、绘制(onDraw)。
下面看下主要实现的效果(实现中间显示文字的View,类似于TextView,可设置字体颜色,字体大小,显示内容等等):
实现过程如下:
1)继承自View,重写其构造方法:
如下:
public DemoTextView01(Context context) { this(context,null); } public DemoTextView01(Context context, AttributeSet attrs) { this(context, attrs,0); } public DemoTextView01(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
2)自定义属性如下:
1,在values目录下创建attrs.xml文件
内容如下(也可将上面的定义直接写在下面的标签内):
<attr name="text" format="string"/> <attr name="textColor" format="color"/> <attr name="textSize" format="dimension"/> <declare-styleable name="DemoTextView01"> <attr name="text"/> <attr name="textColor"/> <attr name="textSize"/> </declare-styleable>2,在自定义View中获取相关的属性值如下(直接在初始化的时候完成,即构造器中):
// 获取到我们自定义的属性值
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DemoTextView01,defStyleAttr,0);
// 遍历取到相关的值
for (int i = 0; i < array.getIndexCount(); i++) {
//取到相关属性的ID值,根据Id匹配取到相关的值
int attr = array.getIndex(i);
switch (attr){
case R.styleable.DemoTextView01_text://指定的属性对应的ID值写法:R.styleable.类名_属性名
mText=array.getString(attr);
break;
case R.styleable.DemoTextView01_textColor:
//取到设置的字体颜色的值,默认的字体颜色为黑色
mTextColor=array.getColor(attr, Color.BLACK);
break;
case R.styleable.DemoTextView01_textSize:
//设置默认值为16sp TypeValue是对sp和dp进行相互的转换(各种尺寸的转换)
mTextSize = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
default:
break;
}
}
array.recycle();
3)初始化画笔及绘制范围如下(也在构造器中完成):
mPaint = new Paint();
mPaint.setTextSize(mTextSize);
mBound = new Rect();
mPaint.getTextBounds(mText,0,mText.length(),mBound);
4)重写onDraw方法进行绘制如下:
@Override protected void onDraw(Canvas canvas) { //设置底色为灰色 并进行绘制 mPaint.setColor(Color.GRAY); canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint); //设置字体颜色为设置的字体颜色,并进行内容的绘制 mPaint.setColor(mTextColor); canvas.drawText(mText,getWidth()/2-mBound.width()/2,getHeight()/2+mBound.height()/2, mPaint); }5)重写onMeasure进行测量(重点)如下:
Android控件测量MeasureSpec共三种模式,如下:
EXACTLY:指的是设置了明确的值或者是MATCH_PARENT。
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT。
UNSPECIFIED:不限制,很少使用。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMode == MeasureSpec.EXACTLY){ width = widthSize; }else { mPaint.setTextSize(mTextSize); mPaint.getTextBounds(mText,0,mText.length(),mBound); float textWidth = mBound.width(); int desire = (int)(getPaddingLeft()+textWidth+ getPaddingRight()); width = desire; } if (heightMode == MeasureSpec.EXACTLY){ height = heightSize; }else { mPaint.setTextSize(mTextSize); mPaint.getTextBounds(mText,0,mText.length(),mBound); float textHeight = mBound.height(); int desire = (int)(getPaddingTop()+textHeight+ getPaddingBottom()); height = desire; } setMeasuredDimension(width,height); }注意:此步骤非常重要如果缺失,则在宽度高度为wrap_content的时候会铺满整个屏幕,如下:
到此为止,自定义控件已经完成了。
自定义控件的使用如下:
xml文件内容:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:text="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jinjin.viewstudy.viewstudy.MainActivity">
<com.jinjin.viewstudy.viewstudy.view.DemoTextView01
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="10dp"
text:text="自定义View的内容"
text:textColor="#ff0000"
text:textSize="30sp"
/>
</RelativeLayout>
注意:红色字体部分为引入命名控件,缺失则不能正常使用。
到此即可实现上述的显示效果。
源码下载:Demo
作者:jinjin10086 发表于2017/2/9 15:30:29 原文链接
阅读:11 评论:0 查看评论