在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节