【Android】 XML 自定义属性——attr、declare-styleable、style、theme、TypedArray 的基本使用

目录

1. attr 自定义属性的类型

2. 声明自定义属性

3. 自定义属性复用

4. 自定义属性之坑

5. XML 布局文件中使用自定义属性——命名空间

6. 使用 style 复用 xml 属性

7. 属性优先级

7.1 View的构造方法

7.2 TypedArray

7.3 全局Theme与局部Theme优先级


1. attr 自定义属性的类型

<attr name="字符串" format="string"/>
<attr name="颜色" format="color"/>
<attr name="尺寸" format="dimension"/>
<attr name="整型" format="integer"/>
<attr name="浮点型" format="float"/>
<attr name="布尔型" format="boolean"/>
<attr name="资源引用" format="reference"/>
<attr name="百分数" format="fraction"/>
<attr name="枚举">
  <enum name="name0" value="0"/>
  <enum name="name1" value="1"/>
</attr>
<attr name="立死亡flag">
  <flag name="name0" value="0"/>
   <flag name="name1" value="1"/>
  <flag name="name2" value="2"/>
</attr>
<attr name="获取多种类型 | 号隔开" format="reference|color|integer"/>

2. 声明自定义属性

<attr name="iconWidth" format="dimension"/>
<attr name="iconHeight" format="dimension"/>

attr 标签属性会在R类下的attr类中生成16进制地址静态常量,比如

public static final class attr {
    public static final int iconWidth = 0x7f010000;
    public static final int iconHeight = 0x7f010001;
}

代码中取属性值方法

int[] attrKeys = {R.attr.iconWidth, R.iconHeight};
TypedArray typedArray = context.obtainStyledAttributes(set, atttrKeys);
float iconWidth = typedArray.getDimension(0, defaultValue);
float iconHeight = typedArray.getDimension(1, defaultValue);

 declare-styleable 标签封装 attr

<declare-styleable name="MyIconView">
    <attr name="iconWidth" format="dimension"/>
    <attr name="iconHeight" format="dimension"/>
</declare-styleable>

使用declare-styleable封装的attr会在R类下的styleable类封装attr类下的16进制地址生成int[]数组,并生成下标索引:

public static final class styleable {

    public static final int[] MyIconView = {
        0x7f010000, 0x7f010001
    };

    public static final int MyIconView_iconWidth = 0;
    public static final int MyIconView_iconHeight = 1;

}

代码中取属性值方法

TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.MyIconView);
float iconWidth = typedArray.getDimension(R.styleable.MyIconView_iconWidth, defaultValue);
float iconHeight = typedArray.getDimension(R.styleable.MyIconView_iconHeight, defaultValue);

3. 自定义属性复用

重复的自定义属性

<declare-styleable name="MyIconView">
    <attr name="icon" format="reference"/>
    <attr name="iconWidth" format="dimension"/>
    <attr name="iconHeight" format="dimension"/>
</declare-styleable>

<declare-styleable name="MyImageView">
    <attr name="icon" format="reference"/>
</declare-styleable>

 复用自定义属性写法

<attr name="icon" format="reference"/>

<declare-styleable name="MyIconView">
    <attr name="icon"/>
    <attr name="iconWidth" format="dimension"/>
    <attr name="iconHeight" format="dimension"/>
</declare-styleable>

<declare-styleable name="MyImageView">
    <attr name="icon"/>
</declare-styleable>

 复用Android SDK已有属性

<declare-styleable name="MyIconView">
    <attr name="android:src"/>
    <attr name="iconWidth" format="dimension"/>
    <attr name="iconHeight" format="dimension"/>
</declare-styleable>

4. 自定义属性之坑

Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x1f

不能定义名称为 SDK 的自定义属性名

<!-- sdk attr -->
android:text
android:textSize
android:textColor

<!-- 自己定义的属性不能定义成上面的属性,不能定义如下 -->

<attr name="text" format="string"/>
<attr name="textSize" format="dimension"/>
<attr name="textColor" format="color"/>

5. XML 布局文件中使用自定义属性——命名空间

  • 系统的命名空间:xmlns:android="http://schemas.android.com/apk/res/android"

通用命名空间:

xmlns:app="http://schemas.android.com/apk/res-auto"

包名命名空间:

xmlns:app="http://schemas.android.com/apk/res/包名"

xmlns:app 是自定义的属性引用名, URL:http://schemas.android.com/apk/res 是默认的资源标识,实际是不可访问的

命名空间作用域:声明到根布局则全局使用,声明到单个 View 则只能在单个 View 内使用

属性的使用 

<com.bin.MyIconView 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher"
    app:iconWidth="35dp"
    app:iconHeight="35dp" />

 android:src 的 : 号是转意的语法,左边的名称是来自哪个命名空间的属性.

6. 使用 style 复用 xml 属性

重复属性

<com.bin.MyIconView 
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:src="@drawable/ic_launcher"
    app:iconWidth="35dp"
    app:iconHeight="35dp" />

<com.bin.MyIconView 
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:src="@drawable/ic_launcher"
    app:iconWidth="35dp"
    app:iconHeight="35dp" />

封装style

<style name="MyIconView">
    <item name="android:layout_width">0dp</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_weight">1"</item>
    <item name="android:src">@drawable/ic_launcher</item>
    <item name="iconWidth">35dp</item>
    <item name="iconHeight">35dp</item>
</style>

注意:SDK的属性需要android:,自定义的属性直接写名字

复用属性后

<com.bin.MyIconView 
    style="@style/MyIconView" />

<com.bin.MyIconView 
    style="@style/MyIconView" />

7. 属性优先级

7.1 View的构造方法

public View(Context context) {
    this(context, null);
}

public MyCustomView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
    this(context, attrs, defStyle, 0);
}

public MyCustomView(Context context, AttributeSet attrs, int defStyle, int defStyleRec) {
    super(context, attrs, defStyle, defStyleRec);
    // TODO:获取自定义属性
}
  • 4个参数的构造方法是API21引入,若有需求请注意版本兼容,一般3个参数的构造方法可以满足需求
  • 代码中 new ,调用第一个构造方法。
  • XML 中调用第二个构造方法。
  • 第三和第四个构造方法需要手动调用。

7.2 TypedArray

context 中返回 TypedArray 的四个方法

  • obtainAttributes(AttributeSet set, int[] attrs)  //从layout设置的属性集中获取attrs中的属性
  • obtainStyledAttributes(int[] attrs)  //从系统主题中获取attrs中的属性
  • obtainStyledAttributes(int resId,int[] attrs)  //从资源文件定义的style中读取属性
  • obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)

参数含义:

  1. AttributeSet set:从layout xml文件为view添加的属性集合。(键值)
  2. int[] attrs:每个方法都有的参数。最终返回的TypedArray只能查找对应数组Id的属性。(键)
  3. int defStyleAttr:从当前Activity设置的Theme中搜索的style。(键值)
  4. int defStyleRes:备用style,当defStyleAttr为0时,并且them中未设置对应此View的defStyleAttr才生效。(键值)
  5. int resId:直接从资源文件中定义的某个style中读取。(键值)

优先级:

  1. 布局中为View显示设置的值 >
  2. 布局中style指定的样式 > 
  3. (defStyleAttr) 布局通过主题中配置的style,代码中指定的style resId > 
  4. (defStyleRes) 代码中指定的style resId。当defStyleAttr为0时,并且them中未设置对应此View的defStyleAttr才生效 >
  5. theme中指定的item attr属性

7.3 全局Theme与局部Theme优先级

Application Theme < Activity Theme  < View style: 三个theme设置了共同属性而值不同的优先级。

例如 TextView 的 android:textColor

// layout
<LinearLayout ...>

<TextView 
    android:id="@+id/tv1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView 
    android:id="@+id/tv2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="#0080FF" />

</LinearLayout>

// style

<!-- Activity Theme -->
<style name="ActivityTextColor">
    <item name="android:textColor">@android:color/white</item>
</style>

<!-- Application Theme -->
<style name="ApplicationTextColor">
    <item name="android:textColor">@android:color/black</item>
</style>

结果

控件ID:tv1 textColor = white
控件ID:tv2 textColor = #0080FF

 

参考:深入理解Android 自定义attr Style styleable以及其应用

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android 中,我们可以使用自定义属性来设置边距。下面是一个示例代码,展示了如何在 XML 布局文件中使用自定义属性来设置边距: 首先,在 res/values/attrs.xml 文件中定义自定义属性: ```xml <resources> <declare-styleable name="CustomView"> <attr name="customMargin" format="dimension" /> </declare-styleable> </resources> ``` 然后,在布局文件中使用自定义属性来设置边距: ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Hello World!" android:layout_margin="@style/CustomView.customMargin" /> </LinearLayout> ``` 在上述示例中,我们在 TextView 的 layout_margin 属性使用了 @style/CustomView.customMargin,这样就可以设置自定义的边距。 当然,你也可以在 Java 代码中使用自定义属性来设置边距。首先,获取自定义属性的值: ```java TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomView); int customMargin = typedArray.getDimensionPixelSize(R.styleable.CustomView_customMargin, 0); typedArray.recycle(); ``` 然后,将获取到的边距值应用到视图: ```java LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.setMargins(customMargin, customMargin, customMargin, customMargin); textView.setLayoutParams(params); ``` 这样就可以通过自定义属性来设置边距了。希望能帮到你!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虚妄狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值