自定義View之圓形TextView
阿新 • • 發佈:2019-02-11
【1】自定義View的屬性 :
在res/values下新建一個attrs.xml檔案,在裡面定義我們的屬性
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="titleText" format="string"/> <attr name="titleTextColor" format="color"/> <attr name="backColor" format="color"/> <attr name="titleTextSize" format="dimension"/> <declare-styleable name="CustomCircleView"> <attr name="titleText"/> <attr name="titleTextColor"/> <attr name="titleTextSize"/> <attr name="backColor"/> </declare-styleable> </resources>
在佈局定義View,這裡定義了5個:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <com.dhl.customview.view.CustomCircleView android:layout_width="100dp" android:layout_height="100dp" app:titleText="123456" app:titleTextColor="@color/colorAccent" android:padding="5dp" android:layout_marginLeft="30dp" android:layout_centerInParent="true" app:titleTextSize="14sp" /> <com.dhl.customview.view.CustomCircleView android:layout_width="100dp" android:layout_height="100dp" app:titleText="123456" app:titleTextColor="@color/colorAccent" android:padding="5dp" android:layout_marginLeft="30dp" android:layout_alignParentRight="true" app:titleTextSize="18sp" /> <com.dhl.customview.view.CustomCircleView android:layout_width="100dp" android:layout_height="100dp" app:titleText="123456" app:titleTextColor="@color/colorAccent" android:padding="5dp" android:layout_marginLeft="30dp" app:backColor="#abdc25" android:layout_alignParentLeft="true" app:titleTextSize="18sp" /> <com.dhl.customview.view.CustomCircleView android:layout_width="100dp" android:layout_height="100dp" app:titleText="123456" app:titleTextColor="@color/colorAccent" android:padding="5dp" android:layout_marginLeft="30dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" app:titleTextSize="18sp" /> <com.dhl.customview.view.CustomCircleView android:layout_width="wrap_content" android:layout_height="wrap_content" app:titleText="123456" app:titleTextColor="@color/colorAccent" android:padding="5dp" android:layout_marginLeft="30dp" app:backColor="#abdc25" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" app:titleTextSize="18sp" /> </RelativeLayout>
【2】在構造方法中獲取自定義屬性:
public CustomCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray a= context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCircleView,defStyleAttr,0); /** * 這個獲得是你實際在layout中設定的屬性個數 */ int n = a.getIndexCount(); for(int i = 0;i<n;i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomCircleView_titleText: titleText = a.getString(attr); break; case R.styleable.CustomCircleView_titleTextColor: titleColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomCircleView_backColor: backColor = a.getColor(attr,Color.GREEN); break; case R.styleable.CustomCircleView_titleTextSize: titleSize = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } a.recycle(); mPaint = new Paint(); mPaint.setTextSize(titleSize); mBound = new Rect(); /** * 獲得繪製文字的寬和高 */ mPaint.getTextBounds(titleText, 0, titleText.length(), mBound); }
獲取自定義屬性,並且遍歷每個屬性,set相應的值。
【3】重寫onMeasure:
MeasureSpce的mode有三種:EXACTLY, AT_MOST,UNSPECIFIED,EXACTLY顧名思義,有了準確的值,一般是固定的寬高度或者match_parent。AT_MOST表示在一個範圍內,一般為wrap_content。UNSPECIFIED表示View能有多大就多大,很少用到。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.e(TAG,"onMeasure");
int width = getMySize(100,widthMeasureSpec);
int height = getMySize(100,heightMeasureSpec);
setMeasuredDimension(width, height);
}
封裝計算相應的寬高
/**
* 計算相應的寬高
* @param defaultSize 預設值
* @param measureSpec
* @return
*/
private int getMySize(int defaultSize, int measureSpec) {
int mySize = defaultSize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED: {//如果沒有指定大小,就設定為預設大小
mySize = defaultSize;
break;
}
case MeasureSpec.AT_MOST: {//如果測量模式是最大取值為size
//我們將自己計算View的大小
mPaint.setTextSize(titleSize);
mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);
float textWidth = mBound.width();
int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
mySize = desired;
break;
}
case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改變它
mySize = size;
break;
}
}
return mySize;
}
主要是對AT_MOST這種情況的處理,這個處理好了,View的寬和高就是對的。
【4】重寫onDraw():
這個主要是把相應View繪製出來,
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e(TAG,"onDraw");
//圓的半徑
int r = Math.min(getMeasuredWidth() / 2,getMeasuredHeight()/2);
//圓心的橫座標
int centerX =r;
//圓心的縱座標
int centerY =r;
Paint paint = new Paint();
paint.setColor(Color.GREEN);
mPaint.setColor(backColor);
//繪製圓
canvas.drawCircle(centerX, centerY, r, mPaint);
mPaint.setColor(titleColor);
//繪製Text
canvas.drawText(titleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
}
一個圓形的TextView就此完成,下面貼出全部程式碼:
public class CustomCircleView extends View {
private static final String TAG = CustomCircleView.class.getSimpleName();
/**
* 文字
*/
private String titleText ;
/**
* 字型顏色
*/
private int titleColor =Color.BLACK ;
/**
* 背景顏色,設定預設顏色
*/
private int backColor = Color.GRAY;
/**
* 色值
*/
private int titleSize ;
/**
*控制文字的範圍
*/
private Rect mBound;
private Paint mPaint;
public CustomCircleView(Context context) {
this(context, null);
}
public CustomCircleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a= context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCircleView,defStyleAttr,0);
/**
* 這個獲得是你實際在layout中設定的屬性個數
*/
int n = a.getIndexCount();
for(int i = 0;i<n;i++)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.CustomCircleView_titleText:
titleText = a.getString(attr);
break;
case R.styleable.CustomCircleView_titleTextColor:
titleColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomCircleView_backColor:
backColor = a.getColor(attr,Color.GREEN);
break;
case R.styleable.CustomCircleView_titleTextSize:
titleSize = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mPaint = new Paint();
mPaint.setTextSize(titleSize);
mBound = new Rect();
/**
* 獲得繪製文字的寬和高
*/
mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e(TAG,"onDraw");
//圓的半徑
int r = Math.min(getMeasuredWidth() / 2,getMeasuredHeight()/2);
//圓心的橫座標
int centerX =r;
//圓心的縱座標
int centerY =r;
Paint paint = new Paint();
paint.setColor(Color.GREEN);
mPaint.setColor(backColor);
//繪製圓
canvas.drawCircle(centerX, centerY, r, mPaint);
mPaint.setColor(titleColor);
//繪製Text
canvas.drawText(titleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.e(TAG,"onMeasure");
int width = getMySize(100,widthMeasureSpec);
int height = getMySize(100,heightMeasureSpec);
setMeasuredDimension(width, height);
}
/**
* 計算相應的寬高
* @param defaultSize 預設值
* @param measureSpec
* @return
*/
private int getMySize(int defaultSize, int measureSpec) {
int mySize = defaultSize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED: {//如果沒有指定大小,就設定為預設大小
mySize = defaultSize;
break;
}
case MeasureSpec.AT_MOST: {//如果測量模式是最大取值為size
//我們將自己計算View的大小
mPaint.setTextSize(titleSize);
mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);
float textWidth = mBound.width();
int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
mySize = desired;
break;
}
case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改變它
mySize = size;
break;
}
}
return mySize;
}
public void setTitleText(String str)
{
titleText = str ;
invalidate();
}
}
OK,下面貼出效果圖
如有問題,請留言。。。