在attrs.xml文件中添加了以下的內容java
<declare-styleable name="SimpleApiTextView"> <attr name="android:text"/> <attr name="titleColor" format="color"/> <attr name="titleTextSize" format="dimension"/> </declare-styleable>
引入了以下包名:android
xmlns:zhy="http://schemas.android.com/apk/res-auto"
具體的代碼以下:canvas
<com.self.view.view.SimpleApiTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="5678" zhy:titleColor="@color/colorPrimary" zhy:titleTextSize="20sp"/>
自定義一個類,繼承android.view.View類,重寫其中的構造函數,在構造函數中,得到自定義參數的屬性。並重寫onDraw方法,繪製對應的文字以及背景色。具體的代碼以下所示:app
package com.self.view.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import com.self.view.R; import com.self.view.common.GraphicsUtil; import com.self.view.common.L; /** * Graphics中簡單Api的練習 * 模仿TextView * Created by Administrator on 2017/6/7 0007. */ public class SimpleApiTextView extends View { private String titleText; private int titleColor; private int titleTextSize; private Paint paint; private float textHeight = 0; public SimpleApiTextView(Context context) { this(context,null); L.i("一個參數的構造函數"); } public SimpleApiTextView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); L.i("倆個參數的構造函數"); } public SimpleApiTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); L.i("三個參數的構造函數"); init(context, attrs,defStyleAttr); } private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { //獲取自定義屬性的值 if(null != attrs){ int count = attrs.getAttributeCount(); for(int i =0;i<count;i++){ L.i("key:"+attrs.getAttributeName(i)+" value:"+attrs.getAttributeValue(i)); } } TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleApiTextView); // TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SimpleApiTextView, defStyleAttr, 0); if(null != typedArray){ titleText = typedArray.getString(R.styleable.SimpleApiTextView_android_text); titleColor = typedArray.getColor(R.styleable.SimpleApiTextView_titleColor, Color.RED); titleTextSize = typedArray.getDimensionPixelSize(R.styleable.SimpleApiTextView_titleTextSize, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics())); L.i("titleText="+titleText+" titleColor="+titleColor+" titleTextSize="+titleTextSize); } typedArray.recycle(); //得到當前Paint對應的文字的長寬 paint = new Paint(); paint.setTextSize(titleTextSize); textHeight = GraphicsUtil.measureTextHeight(paint); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setColor(Color.YELLOW); canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint); paint.setColor(titleColor); // canvas.drawText(titleText,0,textHeight,paint); //計算文字的起始位置 float width = getWidth(); float height = getHeight(); float textWidth = paint.measureText(titleText); canvas.drawText(titleText,(width-textWidth)/2,(height+textHeight)/2,paint); } }
最終構造函數中調用的init方法,變成以下所示的代碼:dom
private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { //獲取自定義屬性的值 if(null != attrs){ int count = attrs.getAttributeCount(); for(int i =0;i<count;i++){ L.i("key:"+attrs.getAttributeName(i)+" value:"+attrs.getAttributeValue(i)); } } TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleApiTextView); // TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SimpleApiTextView, defStyleAttr, 0); if(null != typedArray){ titleText = typedArray.getString(R.styleable.SimpleApiTextView_android_text); titleColor = typedArray.getColor(R.styleable.SimpleApiTextView_titleColor, Color.RED); titleTextSize = typedArray.getDimensionPixelSize(R.styleable.SimpleApiTextView_titleTextSize, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics())); L.i("titleText="+titleText+" titleColor="+titleColor+" titleTextSize="+titleTextSize); } typedArray.recycle(); //得到當前Paint對應的文字的長寬 paint = new Paint(); paint.setTextSize(titleTextSize); textHeight = GraphicsUtil.measureTextHeight(paint); //設置Onclick方法 this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { titleText = getRandowText(); postInvalidate(); } }); } private String getRandowText(){ String text = ""; int temp = (int)(Math.random()*10000); text = temp+""; if(text.length() < 4){ String tempStr = ""; for(int i=0;i<4-text.length();i++){ tempStr+="0"; } text = tempStr+text; } return text; }
原來的代碼,若是你在佈局文件中,將對應的長寬設置成wrap_content的時候,會發現沒有達到本身想要的結果。主要是由於沒有重寫onMeasure方法進行從新測量長寬。ide
MeasureSpec主要用於自定義view的測量。MeasureSpec是一個32位的int值,其中高2位是測量的模式,低30位爲測量的大小。其中測量的模式能夠分爲:EXACTLY、AT_MOST、UNSPECIFIED.這三種模式的說明以下:函數
EXACTLY:默認值,對應的長寬的設置:具體值或者是match_parent佈局
AT_MOST:對應的長寬的設置:wrap_contentpost
UNSPECIFIED:這個屬性比較奇怪,它不指定其大小測量模式,View想多大就多大,一般狀況下在繪製自定義View時纔會使用。this
因此,在自定義View的時候,若是沒有重寫onMeasure方法的話,默認的長寬模式就是EXACTLY.若是須要實現wrap_content的效果,就須要重寫onMeasure方法。
該方法的定義以下:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec,heightMeasureSpec); }
查看該方法的源碼,最終會調用setMeasuredDimension(int measuredWidth,int measuredHeight)方法,將測量後的寬高值設置進去。因此在重寫onMeasure方法之後,必須調用此方法,將最終的結果設置進去。
文中例子中的onMeasure方法,以下所示:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { float viewWidth,viewHeight;//自定義View的寬、高 int widthMode = MeasureSpec.getMode(widthMeasureSpec); if(widthMode == MeasureSpec.EXACTLY){ viewWidth = MeasureSpec.getSize(widthMeasureSpec); }else{ viewWidth = paint.measureText(titleText)+getPaddingLeft()+getPaddingRight(); } int heightMode = MeasureSpec.getMode(heightMeasureSpec); if(heightMode == MeasureSpec.EXACTLY){ viewHeight = MeasureSpec.getSize(heightMeasureSpec); }else{ viewHeight = textHeight+getPaddingBottom()+getPaddingTop(); } setMeasuredDimension((int)viewWidth,(int)viewHeight); }
文章寫的並非特別的好,能夠查看下面的參考地址以及參考書籍
參考地址:http://blog.csdn.net/lmj623565791/article/details/24252901
參考書籍:《Android羣英傳》第三章第3.2節