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

原因是由于接触安卓也这么久了,但是自定义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"我们的命名空间,后面的包路径指的是项目的package
2、在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); 

 

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

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










  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值