原因是由于接触安卓也这么久了,但是自定义view这方面一直没怎么了解, 尤其是对于自定义属性的使用。
由于最近app上需要用到自定义View,于是决定把自定义View的坑填上(毕竟安卓中自定义View是重点也是难点),
可是没想到第一步就遇到了问题。写这博文主要是为了记录错误,也可以为同样遇到这问题的童鞋提供一个解决办法。
首先给出鸿洋大神此博文的传送门传送门。你们可以先过去看看。
由于要用到部分大神的文字才方便解释(不知算不算那啥,有问题联系我,立马删除)
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。[html] view plain copy 在CODE上查看代码片派生到我的代码片<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="titleText" format="string" /> <attr name="titleTextColor" format="color" /> <attr name="titleTextSize" format="dimension" /> <declare-styleable name="CustomTitleView"> <attr name="titleText" /> <attr name="titleTextColor" /> <attr name="titleTextSize" /> </declare-styleable> </resources> 我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。然后在布局中声明我们的自定义View[objc] view plain copy 在CODE上查看代码片派生到我的代码片<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.customview01.view.CustomTitleView android:layout_width="200dp" android:layout_height="100dp" custom:titleText="3712" custom:titleTextColor="#ff0000" custom:titleTextSize="40sp" /> </RelativeLayout> 一定要引入 xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"我们的命名空间,后面的包路径指的是项目的package2、在View的构造方法中,获得我们的自定义的样式[java] view plain copy 在CODE上查看代码片派生到我的代码片/** * 文本 */ PRivate String mTitleText; /** * 文本的颜色 */ private int mTitleTextColor; /** * 文本的大小 */ private int mTitleTextSize; /** * 绘制时控制文本绘制的范围 */ private Rect mBound; private Paint mPaint; public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomTitleView(Context context) { this(context, null); } /** * 获得我自定义的样式属性 * * @param context * @param attrs * @param defStyle */ public CustomTitleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); /** * 获得我们所定义的自定义样式属性 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_titleText: mTitleText = a.getString(attr); break; case R.styleable.CustomTitleView_titleTextColor: // 默认颜色设置为黑色 mTitleTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomTitleView_titleTextSize: // 默认设置为16sp,TypeValue也可以把sp转化为px mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } a.recycle(); /** * 获得绘制文本的宽和高 */ mPaint = new Paint(); mPaint.setTextSize(mTitleTextSize); // mPaint.setColor(mTitleTextColor); mBound = new Rect(); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); } 我们可以看到,步骤我们做的都是一样的。但是在获取自定义属性值得时候就不一样了。上文是这样的:
/** * 获得我们所定义的自定义样式属性 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_titleText: mTitleText = a.getString(attr); break; case R.styleable.CustomTitleView_titleTextColor: // 默认颜色设置为黑色 mTitleTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomTitleView_titleTextSize: // 默认设置为16sp,TypeValue也可以把sp转化为px mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } a.recycle(); 也就是先获取了自定义属性的目录索引值,然后通过switch进行与我们的attrs.xml相匹配,最后进行取值。这样咋看没有什么问题,在这篇博文也没什么问题,
但是如果我们想偷点懒,不在xml中写出任何我们的自定义属性,这时会发生什么?
你肯定会说当然是取代码中你写的默认值啊,非也,非也。照这种写法是不能取到任何默认值!
为什么?看看变色的那句,理解到了吗?
context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);是通过查询我们使用自定义View的时候里面所写出的值,准确的说是保存所有我们写出的值,比如上文中的:
android:layout_width="200dp" android:layout_height="100dp" custom:titleText="3712" custom:titleTextColor="#ff0000" custom:titleTextSize="40sp"它就会找到,android:layout_width,android:layout_height,custom:titleText,custom:titleTextColor,custom:titleTextSize。这几组值,
但是如果我们自定义的属性不写上去呢?只是想控制个控件的大小(事实证明很多情况下你的确不太会去改变控件的其他属性,除非你需要),就会变成只找到android:layout_width,android:layout_height。这时候如果你再通过Switch()去匹配的话,除了android:layout_width,android:layout_height两个分支,其他的都不会被执行,既然没有执行,那么默认值如何取得出?
找到了问题所在,我们就要解决了,解决也很简单,去掉获取目录,不使用switch()语句
每个属性都这样获取:
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);// 默认颜色设置为黑色 mTitleTextColor = a.getColor(attr, Color.BLACK);这样就能保证每个想要设置默认值的能正确的被设置默认值了。
有问题欢迎指正,如引用的部分文字有侵权,请告知我,群殴会立即处理、
新闻热点
疑难解答