步骤
1.定义自己的属性
在res/values/目录下专拣attrs.xml文件如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <!--format 的类型:string,color,demension,integer,enum,reference,float,boolean,fraction,flag等;想要详细学习可以去Google查看--> <!--定义一个样式,一个样式包括多个属性--> <declare-styleable name="CustomView"> <!--定义属性名字,及其类型--> <attr name="myText" format="string"/> <attr name="myTextColor" format="color"/> <attr name="myBackgroundColor" format="color"/> <attr name="myTextSize" format="dimension"/> </declare-styleable> </resources>
2.定义自己的View
package netclientdemo.example.com.customview; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; /** * Created by liaoli on 15-11-24. */ public class CustomView_1 extends View { private int backgroundColor; private Rect mBound; private Paint mPint; /** * 要显示的文本内容 */ private String text; /** * 文本显示的颜色 */ private int textColor; /** * */ private int textSize; private Canvas mcanvas; public CustomView_1(Context context) { this(context, null); } public CustomView_1(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomView_1(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /** * 获取我们字自定义的样式属性,TypedArray可以拿到我们所有自定义的属性,并获取我们在Xml中给我们自定义属性赋的值 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0); /** * 下面获取在xml中的赋值 * <netclientdemo.example.com.customview.CustomView_1 * android:layout_width="wrap_content" * android:layout_height="wrap_content" * custom:myText="@string/hello_world" * custom:myTextColor="#fbff38c1" * custom:myBackgroundColor="#91ff84" * android:padding="10dp" * custom:myTextSize="20sp"> * </netclientdemo.example.com.customview.CustomView_1> */ /** * 此时我们text值为@string/hello_world指向的字符串 */ text = a.getString(R.styleable.CustomView_myText); /** * textColor的值为#fbff38c1对应的颜色的Int值,如果没有设置这个值则Color.BLACK作为默认值 */ textColor = a.getColor(R.styleable.CustomView_myTextColor, Color.BLACK); backgroundColor = a.getColor(R.styleable.CustomView_myBackgroundColor, Color.WHITE); textSize = a.getDimensionPixelSize(R.styleable.CustomView_myTextSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); // int n = a.getIndexCount(); // for (int i = 0; i < n; i++) { // int attr = a.getIndex(i); // switch (attr) { // case R.styleable.CustomView_myText: // // text = a.getString(attr); // // break; // case R.styleable.CustomView_myTextColor: // // textColor = a.getColor(attr, Color.BLACK); // // break; // case R.styleable.CustomView_myBackgroundColor: // // backgroundColor = a.getColor(attr, Color.WHITE); // // break; // case R.styleable.CustomView_myTextSize: // // textSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); // // break; // // } // } a.recycle(); mPint = new Paint(); mPint.setTextSize(textSize); mBound = new Rect(); mPint.getTextBounds(text, 0, text.length(), mBound); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec); int widthMeasureSize = MeasureSpec.getSize(widthMeasureSpec); int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec); int heightMeasureSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMeasureMode == MeasureSpec.EXACTLY) { width = widthMeasureSize; } else { mPint.setTextSize(textSize); mPint.getTextBounds(text, 0, text.length(), mBound); float textWidth = mBound.width(); int wrapWidth = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = wrapWidth; } if (heightMeasureMode == MeasureSpec.EXACTLY) { height = heightMeasureSize; } else { mPint.setTextSize(textSize); mPint.getTextBounds(text, 0, text.length(), mBound); float textHeight = mBound.height(); int wrapHeight = (int) (getPaddingTop() + textHeight + getPaddingBottom()); height = wrapHeight; } setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { //super.onDraw(canvas); mPint.setColor(backgroundColor); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPint); mPint.setColor(textColor); canvas.drawText(text, getMeasuredWidth() / 2 - mBound.width() / 2, getMeasuredHeight() / 2 + mBound.height() / 2, mPint); } }
3.应用自定义属性
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <netclientdemo.example.com.customview.CustomView_1 android:layout_width="wrap_content" android:layout_height="wrap_content" custom:myText="@string/hello_world" custom:myTextColor="#fbff38c1" custom:myBackgroundColor="#91ff84" android:padding="10dp" custom:myTextSize="20sp"> </netclientdemo.example.com.customview.CustomView_1> </RelativeLayout>这里要注意:
命名空间:
Android studio 为: http://schemas.android.com/apk/res-auto 后面不用加报名
Eclipse为 :http://schemas.android.com/apk/res/包名
效果:
之所以重写onMeasure方法是要测量wrap_content的宽高。
源码:http://pan.baidu.com/s/1hqJdUuw