2、在View的构造方法中获得我们自定义的属性
3、重写onMesure
4、重写onDraw
3这个步骤不是必须,当然了大部分情况下还是需要重写的。
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="txtName" format="string"/> <attr name="txtColor" format="color"/> <attr name="txtSize" format="dimension" /> <declare-styleable name="titleStyle"> <attr name="txtName"/> <attr name="txtColor"/> <attr name="txtSize"/> </declare-styleable> </resources>
定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;
编写的时候工具会提醒你使用哪种,不知道也可以Google搜索下
接下来就自定义View
public class CustomTitleView extends View{ private String txtName; private int txtColor,txtSize; private Paint mPaint; private Rect mBounds; public CustomTitleView(Context context) { this(context, null); } public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) { //具体操作 } }
定义完自定义的View ,就该调用我们自定义的View了。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:title="http://schemas.android.com/apk/res/com.example.androidDemo" 《》 android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.androidDemo.View.CustomTitleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:padding="5dp" title:txtName="你好" title:txtColor="#ffffff" title:txtSize="16sp"/> </RelativeLayout>
注意代码中的这行,自定义命名空间,com.example.androidDemo是项目包路径
xmlns:title="http://schemas.android.com/apk/res/com.example.androidDemo"
使用自定义命名空间:
title:txtName="你好" title:txtColor="#ffffff" title:txtSize="16sp"
在View的构造方法中,获得我们的自定义的样式
public class CustomTitleView extends View{ private String txtName; private int txtColor,txtSize; private Paint mPaint; private Rect mBounds; public CustomTitleView(Context context) { this(context, null); } public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,R.styleable.titleStyle,defStyleAttr,0); int n = typedArray.getIndexCount(); for (int i = 0; i < n; i++){ int attr = typedArray.getIndex(i); switch (attr){ case 0: txtName = typedArray.getString(attr); break; case 1: txtColor = typedArray.getColor(attr, Color.BLACK); break; case 2: txtSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } typedArray.recycle(); /** * 获得绘制文本的宽和高 */ mPaint = new Paint(); mPaint.setTextSize(txtSize); // mPaint.setColor(mTitleTextColor); mBounds = new Rect(); mPaint.getTextBounds(txtName, 0, txtName.length(), mBounds); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height ; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(txtSize); mPaint.getTextBounds(txtName, 0, txtName.length(), mBounds); float textWidth = mBounds.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired; } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(txtSize); mPaint.getTextBounds(txtName, 0, txtName.length(), mBounds); float textHeight = mBounds.height(); int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom()); height = desired; } setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(txtColor); canvas.drawText(txtName, getWidth() / 2 - mBounds.width() / 2, getHeight() / 2 + mBounds.height() / 2, mPaint); } }
其中
MeasureSpec.EXACTLY判断你传人的宽,高是不是精确赋值android:layout_width="wrap_content"
android:layout_height="wrap_content"
如果是wrap_content,
mPaint.setTextSize(txtSize); mPaint.getTextBounds(txtName, 0, txtName.length(), mBounds); float textWidth = mBounds.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired;
如果是200dp这类精确的宽高值,
if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; }
效果图 ,是不是很好用呢