Android(安卓)自定义View (三部曲)
16lz
2021-01-24
设置自定义View的属性(第一部曲)
首先,我们需要创建一个attr.xml文件,在这个文件中,我们定义好View的属性和相关的数据类型。
<resources> <attr name="text" format="string" /> <attr name="textSize" format="dimension" /> <attr name="textColor" format="color" /> <declare-styleable name="CustomView"> <attr name="text" /> <attr name="textSize" /> <attr name="textColor" /> declare-styleable>resources>
其中,format支持的类型有enum、boolean、color、dimension、flag、float、fraction、integer、reference、string类型。
如果同学们想具体知道attr属性的定义的话,建议同学们去阅读这位博主的博文Android 自定义view (一)——attr 理解
写一个继承View的类,并重写里面的onMeasure和onDraw方法 (第二部曲)
public class CustomView extends View { /** * 测得的自定义view的宽 */ int width; /** * 测得的自定义view的高 */ int height; /** * 文本 */ private String mText; /** * 文本颜色 */ private int mTextColor; /** * 文本大小 */ private int mTextSize; private Paint mPaint; /** * 文本绘制的范围 */ private Rect mTextBound; /** * 矩阵的四个参数 * --Rect rect=new Rect(100,100,300,600); 两个点 ==> 左上,右下 * --but右下角(300,600)其实是不在这个矩形里面的 * --这个矩形实际表示的区域是:(100,100,299,599) */ public CustomView(Context context) { this(context, null); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * 获得我自定义的样式属性 * * @param context * @param attrs * @param defStyle 默认的Style */ public CustomView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); /** * 获得我们所定义的自定义样式属性 * TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组 在使用完成后,一定要调用recycle方法 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView, defStyle, 0); int n = a.getIndexCount(); for(int i =0;iint attr = a.getIndex(i); switch (attr){ case R.styleable.CustomView_text: mText = a.getString(attr); break; case R.styleable.CustomView_textColor: mTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomView_textSize: mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics())); break; } } a.recycle();//一定要调用,否则这次的设定会对下次的使用造成影响(回收资源) /** * 获得绘制文本的宽和高 */ mPaint = new Paint(); mTextBound = new Rect(); mPaint.setTextSize(mTextSize); mPaint.getTextBounds(mText, 0, mText.length(), mTextBound); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); /** * 设置宽度 */ if(widthMode == MeasureSpec.EXACTLY){ width = widthSize; }else { int desiredByText = getPaddingLeft() + mTextBound.width() + getPaddingRight(); width = desiredByText; } /*** * 设置高度 */ if(heightMode == MeasureSpec.EXACTLY){ height = heightSize; }else { mPaint.setTextSize(mTextSize); mPaint.getTextBounds(mText,0,mText.length(),mTextBound); int desire = getPaddingTop() + getPaddingBottom() + mTextBound.height(); height = Math.min(desire,heightSize);//无论如何都不能超过view的高度 } setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { mPaint.setColor(mTextColor); mPaint.setStyle(Paint.Style.FILL); /** * -计算了描绘字体需要的范围 * * -y是 基准线,不是字串符的底部 就像 英文的第三根线 */ canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); }}
现在,我们回过头来看一下onMeasure方法,顾名思义,这个方法的主要功能就是测量我们自定义view的宽和高。
和onMeasure方法相关的有一个叫做MeasureSpec的类,这个类封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。
MeasureSpec有三种模式,分别是
1. EXACTLY
设置了明确的值或者是MATCH_PARENT,模式为EXACTLY
2. AT_MOST
表示子布局限制在一个最大值内,一般为WARP_CONTENT
3. UNSPECIFIED
表示视图可以是任意的大小,没有任何限制。
完成我们的xml布局文件(第三部曲)
记得加上命名空间AS建议我们这样写 xmlns:yuan="http://schemas.android.com/apk/res-auto"
"http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:yuan="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.motoyuan.myapplication.MainActivity"><com.motoyuan.myapplication.CustomView android:layout_width="382dp" android:layout_height="382dp" android:padding="10dp" yuan:text="8796" yuan:textColor="#ff0000" yuan:textSize="30sp" />
如此一来,一个简单的自定义View就完成了
更多相关文章
- Service与Android系统设计(3)
- Android横竖屏要解决的问题
- 深入浅析Android的自定义布局
- Android(安卓)App组件之Fragment说明和示例
- Android状态栏
- 9月26号 Android(安卓)SQLiteDatabase 的相关学习记录
- 20172321 2017-2018-2 《程序设计与数据结构》第11周学习总结
- Android(安卓)Fragment---创建Fragment
- Android中自定义控件和属性