其实这一篇的代码是在一个周之前学习的,这里做复习用吧。
首先 我们了解一下自定义控件的一些属性以及用法:
首先先了解下自定义view的属性吧:
目前已知的属性:
reference 资源类型,通常是@开头,例如@+id/XXXX
string 字符串类型,通常是文字信息
dimension 浮点类型,通常是尺寸度量
color 颜色类型 通常是颜色16进制代码,支持ARBG
boolean 布尔类型 true和false
enum 枚举类型,通常是代表这个属性提供了几种值来进行选择,并且只能选择这几种中的一个
flag 与enum基本没有区别。
integer 整数类型,通常是整数
在values文件夹下新建attrs.xml :写法如下
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="viewtext" format="string"/>
<attr name="viewSize" format="dimension"/>
<attr name="viewColor" format="color"/>
<attr name="isCircle" format="boolean"/>
<!-- 如果即支持string 又支持reference的话--!>
<!-- <attr name="this" format="string|reference"/>--!>
<declare-styleable name="customText">
<attr name="viewtext"/>
<attr name="viewSize"/>
<attr name="viewColor"/>
<attr name="isCircle"/>
</declare-styleable>
</resources>
在这里我定义了控件的text 、大小、颜色、和一个布尔值 。这些属性
那么在attrs中定义了属性的话,我们如何在代码中获得这些属性呢:
记得在自定义view时重写的三个构造方法,第三个构造方法便是用来解析自定义属性的:
public MyCustom(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
// 使用context对象获得我们自定义的属性的值,attrs是我们xml中使用的属性集合,其中包括属性名和属性值等相关信息,后面是我们自定义的属性,也就是我们定义的declare-styleable。
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.customText);
// 使用相应的方法获取各个类型属性的值,第二个参数是获取不到属性值默认的属性值。
mText = typedArray.getString(R.styleable.customText_viewtext);
mTextSize = typedArray.getDimension(R.styleable.customText_viewSize, 16);
mTextColor = typedArray.getColor(R.styleable.customText_viewColor, Color.BLACK);
isCircle = typedArray.getBoolean(R.styleable.customText_isCircle, false);
// 没啥,google推荐的,使用完及时释放
typedArray.recycle();
initPaint();
}
下面是我复习的一点Paint的用法和自定义view测量大小写的一点东西:
当时我是画了一个圆,然后呢,我在想,能不能再圆上写上字,然后让字居中显示,我在xml中写了:
android:text="HELLO"
发现然并卵,然后我发现,我们要在代码中给控件画上字,然后设置文字的显示位置,这里还用到了一点字体测量的知识(FontMetrics这个和字体相关的重要的类),然后为了证实我们的居中位置判断的没错,特意给控件画上了一条中心线。
关于字体测量这一块:
爱哥的自定义控件其实很简单有非常详细非常全面的介绍 。
效果如下图
public class MyCustom extends View {
private Context mContext;
private String mText;
private float mTextSize;
private boolean isCircle;
private int mTextColor;
private Paint mPaint;
public MyCustom(Context context) {
this(context, null);
}
public MyCustom(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyCustom(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
// 使用context对象获得我们自定义的属性的值,attrs是我们xml中使用的属性集合,其中包括属性名和属性值等相关信息,后面是我们自定义的属性,也就是我们定义的declare-styleable。
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.customText);
// 使用相应的方法获取各个类型属性的值,第二个参数是获取不到属性值默认的属性值。
mText = typedArray.getString(R.styleable.customText_viewtext);
mTextSize = typedArray.getDimension(R.styleable.customText_viewSize, 16);
mTextColor = typedArray.getColor(R.styleable.customText_viewColor, Color.BLACK);
isCircle = typedArray.getBoolean(R.styleable.customText_isCircle, false);
// 没啥,google推荐的,使用完及时释放
typedArray.recycle();
initPaint();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//测量控件的宽和高
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//在这里判断是绘制圆形还是正方形
if (isCircle) {
/*
* 1.先画圆,
* 2.其次 文字
*/
mPaint.setColor(Color.GRAY);
//画圆,这里的参数是: 圆心的坐标x,y,圆的半径,和画笔
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, canvas.getHeight() / 2, mPaint);
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
//文字的x轴坐标
//获取text的宽度 (Paint.measureText()这个方法可以直接获取text的宽度)
float textWidth = mPaint.measureText(mText);
//计算text开始的横坐标: 圆半径/2 - text宽度/2
float x = (canvas.getWidth() - textWidth) / 2;
//文字的y轴坐标 (这里用到FontMetrics不详细注释,之后会详细学习这一块)
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float y = canvas.getHeight() / 2 + (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;
canvas.drawText(mText, x, y, mPaint);//这里的y是指的text的基线的位置
} else {
mPaint.setColor(Color.GRAY);
float left = getLeft();
float top = getTop();
float bottom = getBottom();
float right = getRight();
canvas.drawRect(left, top, right, bottom, mPaint);
// Log.i("NUM-->", canvas.getDensity()+"");
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
float textWidth = mPaint.measureText(mText);
float x = canvas.getWidth() / 2 - textWidth / 2;
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float y = canvas.getHeight() / 2 + (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;
canvas.drawText(mText, x, y, mPaint);
}
//画出控件的水平中心线
mPaint.setColor(Color.YELLOW);
// float startX, float startY, float stopX, float stopY,
canvas.drawLine(0, canvas.getHeight() / 2, canvas.getWidth(), canvas.getHeight() / 2 + 1, mPaint);
}
private int measureWidth(int widthMeasureSpec) {
int result;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = 200;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private int measureHeight(int heightMeasureSpec) {
int result;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
/* 根据测量模式和设置的大小来进行测量
* 测量模式有三种类型
* 1、EXACTLY 精确模式。用户设置了精确的宽和高或者是设置了match_parent充满父控件
* 2、AT_MOST 用户设置了warp_content
* 3.UNSPECTIFIED 什么都不设置。一般是画的控件
* */
if (specMode == MeasureSpec.EXACTLY) {
//如果用户设置的精确模式,则返回用户设置的值
result = specSize;
} else {
//如果用户没有设置精确模式,那么我们首先定义一个标准值,
result = 200;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
}
本人菜鸟,正在努力学习中。。有什么错误,希望大家指导。