首页 > 系统 > Android > 正文

鸿洋大神博文Android 自定义View (一)中自定义属性所遇到的坑

2019-11-08 00:29:21
字体:
来源:转载
供稿:网友

原因是由于接触安卓也这么久了,但是自定义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); 

这样就能保证每个想要设置默认值的能正确的被设置默认值了。

有问题欢迎指正,如引用的部分文字有侵权,请告知我,群殴会立即处理、


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表