其實(shí)這一篇的代碼是在一個(gè)周之前學(xué)習(xí)的,這里做復(fù)習(xí)用吧说搅。
首先 我們了解一下自定義控件的一些屬性以及用法:
首先先了解下自定義view的屬性吧:
目前已知的屬性:
reference 資源類型,通常是@開(kāi)頭,例如@+id/XXXX
string 字符串類型葛闷,通常是文字信息
dimension 浮點(diǎn)類型,通常是尺寸度量
color 顏色類型 通常是顏色16進(jìn)制代碼禀苦,支持ARBG
boolean 布爾類型 true和false
enum 枚舉類型既荚,通常是代表這個(gè)屬性提供了幾種值來(lái)進(jìn)行選擇,并且只能選擇這幾種中的一個(gè)
flag 與enum基本沒(méi)有區(qū)別搀绣。
integer 整數(shù)類型飞袋,通常是整數(shù)
在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 、大小链患、顏色巧鸭、和一個(gè)布爾值 。這些屬性
那么在attrs中定義了屬性的話麻捻,我們?nèi)绾卧诖a中獲得這些屬性呢:
記得在自定義view時(shí)重寫的三個(gè)構(gòu)造方法纲仍,第三個(gè)構(gòu)造方法便是用來(lái)解析自定義屬性的:
public MyCustom(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
// 使用context對(duì)象獲得我們自定義的屬性的值,attrs是我們xml中使用的屬性集合贸毕,其中包括屬性名和屬性值等相關(guān)信息郑叠,后面是我們自定義的屬性,也就是我們定義的declare-styleable明棍。
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.customText);
// 使用相應(yīng)的方法獲取各個(gè)類型屬性的值乡革,第二個(gè)參數(shù)是獲取不到屬性值默認(rèn)的屬性值。
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);
// 沒(méi)啥击蹲,google推薦的署拟,使用完及時(shí)釋放
typedArray.recycle();
initPaint();
}
下面是我復(fù)習(xí)的一點(diǎn)Paint的用法和自定義view測(cè)量大小寫的一點(diǎn)東西:
當(dāng)時(shí)我是畫了一個(gè)圓,然后呢歌豺,我在想推穷,能不能再圓上寫上字,然后讓字居中顯示类咧,我在xml中寫了:
android:text="HELLO"
發(fā)現(xiàn)然并卵馒铃,然后我發(fā)現(xiàn),我們要在代碼中給控件畫上字痕惋,然后設(shè)置文字的顯示位置区宇,這里還用到了一點(diǎn)字體測(cè)量的知識(shí)(FontMetrics這個(gè)和字體相關(guān)的重要的類),然后為了證實(shí)我們的居中位置判斷的沒(méi)錯(cuò)值戳,特意給控件畫上了一條中心線议谷。
關(guān)于字體測(cè)量這一塊:
愛(ài)哥的自定義控件其實(shí)很簡(jiǎn)單有非常詳細(xì)非常全面的介紹 。
效果如下圖
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對(duì)象獲得我們自定義的屬性的值堕虹,attrs是我們xml中使用的屬性集合卧晓,其中包括屬性名和屬性值等相關(guān)信息芬首,后面是我們自定義的屬性,也就是我們定義的declare-styleable逼裆。
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.customText);
// 使用相應(yīng)的方法獲取各個(gè)類型屬性的值郁稍,第二個(gè)參數(shù)是獲取不到屬性值默認(rèn)的屬性值。
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);
// 沒(méi)啥胜宇,google推薦的耀怜,使用完及時(shí)釋放
typedArray.recycle();
initPaint();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//測(cè)量控件的寬和高
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//在這里判斷是繪制圓形還是正方形
if (isCircle) {
/*
* 1.先畫圓,
* 2.其次 文字
*/
mPaint.setColor(Color.GRAY);
//畫圓桐愉,這里的參數(shù)是: 圓心的坐標(biāo)x,y,圓的半徑财破,和畫筆
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, canvas.getHeight() / 2, mPaint);
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
//文字的x軸坐標(biāo)
//獲取text的寬度 (Paint.measureText()這個(gè)方法可以直接獲取text的寬度)
float textWidth = mPaint.measureText(mText);
//計(jì)算text開(kāi)始的橫坐標(biāo): 圓半徑/2 - text寬度/2
float x = (canvas.getWidth() - textWidth) / 2;
//文字的y軸坐標(biāo) (這里用到FontMetrics不詳細(xì)注釋,之后會(huì)詳細(xì)學(xué)習(xí)這一塊)
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);
/* 根據(jù)測(cè)量模式和設(shè)置的大小來(lái)進(jìn)行測(cè)量
* 測(cè)量模式有三種類型
* 1仅财、EXACTLY 精確模式狈究。用戶設(shè)置了精確的寬和高或者是設(shè)置了match_parent充滿父控件
* 2、AT_MOST 用戶設(shè)置了warp_content
* 3.UNSPECTIFIED 什么都不設(shè)置盏求。一般是畫的控件
* */
if (specMode == MeasureSpec.EXACTLY) {
//如果用戶設(shè)置的精確模式抖锥,則返回用戶設(shè)置的值
result = specSize;
} else {
//如果用戶沒(méi)有設(shè)置精確模式,那么我們首先定義一個(gè)標(biāo)準(zhǔn)值碎罚,
result = 200;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
}
本人菜鳥(niǎo)磅废,正在努力學(xué)習(xí)中。荆烈。有什么錯(cuò)誤拯勉,希望大家指導(dǎo)。