Android View自定义参数declare-styleable介绍与使用

背景:

我们在开发过程,常常在布局中引入一些定义好的View,这些view需要一些属性值,这些值是怎么来的?我们是否可以自己定义一些自己的属性值,答案是可以的。

这时候我们可以借助declare-styleable来实现,一般这个declare-styleable出现在自定义view比较多。

declare-styleable是什么?

它是一种资源定义,通过xml管理

declare-styleable如何使用?

1.xml资源的新建

declare-styleable是一种资源,所以在项目中应该出现资源文件夹下values,在资源文件夹下新建一个自己的declare-styleable的xml管理文件,attr,
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CircleImage">
        <attr name="hasBorder" format="boolean"/>
        <attr name="borderWidth" format="dimension"/>
        <attr name="borderColor"  format="color"/>
    </declare-styleable>
</resources>

根节点是resources。

declare-styleable节点有一个自己的name,name下方是attr 的数组节点,我们可以定义我们想要的参数和类型。

<attr name="borderWidth" format="dimension"/>

name=参数名,format=类型

format都有哪些类型?

color:颜色值
dimension:dimen值
integer:整型
boolean:布尔型
string:字符串
enum:枚举
flags:标签数组,value int型,
float:浮点
fraction:百分数
reference:引用类型,需要搭配资源类型

二、小试牛刀

1.自定义数据类型

<declare-styleable name="testAttr">
    <attr name="colors" format="color" />
    <attr name="age" format="integer" />
    <attr name="mheights" format="float" />
    <attr name="name" format="string" />
    <attr name="flags" format="flags">
        <flag name="f1" value="1" />
        <flag name="f2" value="2" />
        <flag name="f3" value="3" />
    </attr>
    <attr name="enums" format="enum">
        <enum name="a" value="97" />
        <enum name="b" value="98" />
        <enum name="c" value="99" />
        <enum name="d" value="100" />
    </attr>
    <attr name="sex" format="boolean" />

    <attr name="size" format="reference|dimension" />

    <attr name="length" format="dimension" />
    <attr name="per" format="fraction"/>


</declare-styleable>

以上我们定义了一组styleable,name为testAttr

2.在layout进行引用

<com.example.wiik.testdemo.view.TestAttrView
xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:age="10"
    app:colors="@color/color_222222"
    app:enums="c"
    app:flags="f1"
    app:mheights="180.0"
    app:length="@dimen/android_public_space_23px"
    app:name="zhangshan"
    app:sex="true"
    app:size="@dimen/android_public_space_20dp"
    app:per="80%"
    />
如果我们需要引用资源自定义,需要引进:
xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:加自定义名称(app)

如果该类型是enum或者flags,该值已定义好了,直接选择就行,且这两个参数的值只能是int类型否则会报错

 error: invalid value 'true' for <flag>; must be an integer.

 error: invalid value 'true' for <enum>; must be an integer.

这个和我们经常用的一些官方的View设置参数很像,

<attr name="visibility">

    <enum name="visible" value="0" />

    <enum name="invisible" value="1" />

    <enum name="gone" value="2" />
</attr>
<attr name="layout_width" format="dimension">
    <enum name="fill_parent" value="-1" />
    <enum name="match_parent" value="-1" />
    <enum name="wrap_content" value="-2" />
</attr>

如果我们在declare-styleable 申明了aatr的类型,在使用中,也应该指定类型,否则会报错

这里面特别说明的地方是:fraction

fraction是百分比类型,分为base和pbase,

app:per="80%p"是pbase意思,
app:per="80%"是base

以上两种会在解析的时候进行详细介绍

3.解析

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typed = context.obtainStyledAttributes(attrs, R.styleable.testAttr);

        if (typed == null)
            return;
        int color = typed.getColor(R.styleable.testAttr_colors, 0);
        boolean sex = typed.getBoolean(R.styleable.testAttr_sex, false);
        int age = typed.getInt(R.styleable.testAttr_age, 0);
        float height = typed.getFloat(R.styleable.testAttr_mheights, 0);
        String name = typed.getString(R.styleable.testAttr_name);
//        int flag = typed.getInt(R.styleable.testAttr_flags, 0);
        int enums = typed.getInt(R.styleable.testAttr_enums, -1);
        float size = typed.getDimension(R.styleable.testAttr_size, -1);
        float length = typed.getDimension(R.styleable.testAttr_length, -1);

        float per = typed.getFraction(R.styleable.testAttr_per, 1, 1, 0);



        int type = typed.getType(R.styleable.testAttr_flags);
        String typeMsg = "";
        if (type == TypedValue.TYPE_STRING) {
            typeMsg = "TYPE_STRING";
        } else if (type == TypedValue.TYPE_FLOAT) {
            typeMsg = "TYPE_FLOAT";
        } else if (type == TypedValue.TYPE_INT_HEX) {
            typeMsg = "TYPE_INT_HEX";
        }


        //资源释放
        typed.recycle();


    }

3.1解析一般先获取TypedArray

TypedArray typed = context.obtainStyledAttributes(attrs, R.styleable.testAttr);

然后根据自己的定义类型,获取相应的值。

我们定义的attr索引名称为=styleable_name

比如我们的styleable name=testAttr

所以age的索引key=testAttr_age(R.styleable.testAttr_age)

最后我们获取的值如下

特别说明:

1、这里特别介绍一下,使用完TypedArray一定要释放掉,因为这些都是资源,如果不释放,长时间占用会导致OOM

2、关于 typed.getFraction()的使用

public float getFraction(@StyleableRes int index, int base, int pbase, float defValue)

index:name的索引
base:base倍数
pbase:parent 倍数
defValue:默认值

  • base,返回的百分比为属性值乘以 base。
  • pbase,返回的百分比为属性值乘以 pbase。
  • base 和 pbase 同时设置只会有一个生效,因为上面 return 中只能使用一个参数。
  • base 表示百分比资源的基值,返回结果为 nn% * base 的结果值。
  • pbase 表示 %p 形态百分比资源的基值,返回结果为 nn%p * pbase 的结果值。

测试:

app:per="100%p"

 app:per="100%"

3.关于flags和enum的值

这两个child value只能是int,否则会报错 

 error: invalid value 'true' for <flag>; must be an integer.

 error: invalid value 'true' for <enum>; must be an integer.

4.精度丢失

typed.getFraction存在精度丢失情况,并不是你设置80%,就返回0.8,目前测试存在精度丢失,返回是0.79999..,如果对精度要求比较准确的,谨慎使用fraction来作为标识。


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值