自定义View(零)自定义属性

一、为什么要自定义属性


如果想使用一个属性,那么首先这个属性应该存在,所以,如果我们想在自定义View中扩展一些自定义的属性,我们就应该去创建出来这些属性,否则只能使用View的属性,因为所有的控件都继承自View

二、自定义属性的步骤


  1. 创建自定义View

    public class LinearLayout extends ViewGroup {}
    
  2. 创建Value/attrs.xml文件,编写declare-styleable、attr等标签,创建自定义属性

    <resources>
        ……
        <attr name="orientation">
            <enum name="horizontal" value="0" />
            <enum name="vertical" value="1" />
        </attr>
        <declare-styleable name="LinearLayout">
            <attr name="orientation" />
            <attr name="gravity" />
            <attr name="baselineAligned" format="boolean" />
            <attr name="weightSum" format="float" />
            <attr name="measureWithLargestChild" format="boolean" />
            <attr name="divider" />
            <attr name="showDividers">
                <flag name="none" value="0" />
                <flag name="beginning" value="1" />
                <flag name="middle" value="2" />
                <flag name="end" value="4" />
            </attr>
            <attr name="dividerPadding" format="dimension" />
        </declare-styleable>
    </resources>
    

    带有format的是自定义的,没有的是直接使用系统的

  3. xml中使用自定义View,使用自定义属性

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:pftext="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:background="@color/white"
        android:fitsSystemWindows="true">
        
    </LinearLayout>
    
    

    xmlns:android="http://schemas.android.com/apk/res/android"是命名空间,这里代表是到android系统里去查找相关属性,只有引入了命名空间,XML文件才知道下面使用的属性应该去哪里查找

    所以,我们自定义属性也要声明命名空间:
    xmlns:空间名称="http://schemas.android.com/apk/我们的包名"
    这样就会到我们的应用程序包中查找相关属性

    现在,Android Studio会自动为我们生成命名空间:
    xmlns:空间名称="http://schemas.android.com/apk/res-auto"
    自动查找

    空间名称,随便起一个就行

  4. 在自定义View的构造方法中,通过TypeArray获取自定义属性值

    public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        
        // 1. 获取TypedArray
        final TypedArray a = context.obtainStyledAttributes(
                    attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
    
        // 2. 获取相应的属性值
        int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
        if (index >= 0) {
            setOrientation(index);
        }
    
        // 3. 释放TypedArray
        a.recycle();
     
    }
    

三、declare-styleable


declare-styleable就是一个属性集的声明加分类,name一般都是用我们自定义View的名字

首先,使用这个标签方便我们自己查看,每两个declare-styleable标签之间都是一个自定义view的自定义属性,并且方便系统为我们分组,并在R文件生成每个属性对应的索引值,TypedArray正好需要通过此索引值获取属性。

public static final int[] AppBarLayout = {
    0x010100d4, 0x7f01006b, 0x7f010076
};
public static final int AppBarLayout_android_background = 0;
public static final int AppBarLayout_elevation = 1;
public static final int AppBarLayout_expanded = 2;

可以不使用declare-styleable标签,那么类似上面代码这种工作就要我们自己去做了

四、AttributeSet与TypedArray


Attributeset是一个属性的集合,它内部就是一个XML解析器,帮我们将布局文件中该控件的所有属性解析出来,并以key-value的键值对形式维护起来。

Attributeset可以获取到属性值,但是,如果设置值时使用的是引用类型(例:@dimen/dp_16),AttributeSet获取到的属性值将会是类似@213456这种字符串

如果使用AttributeSet去获得最终的属性值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程,可以直接获得属性值

五、TypedArray.recycle()


程序在运行时维护了一个TypedArray的池,程序调用时,会向该池中请求一个实例,用完之后,调用recycle()方法来释放该实例,从而使其可被其他模块复用

TypedArray使用的是池+单例模式,如果不这样的话TypedArray会随着 Activity的每一次Create而频繁的创建array,对内存和性能是一个不小的开销,如果不使用池模式,每次都让GC来回收,很可能就会造成OutOfMemory。

六、format取值类型


共有11种类型:

1. reference:资源ID
属性定义:

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

属性使用:

android:layout="@layout/item"

2. color:颜色值
属性定义:

<attr name="colorAccent" format="color" />

属性使用:

android:colorAccent="#00FF00"

3. boolean:布尔值
属性定义:

<attr name="showTitle" format="boolean" />

属性使用:

android:showTitle="true"

4. dimension:尺寸值
属性定义:

<attr name="padding" format="dimension" />
<attr name="textSize" format="dimension" />

属性使用:

android:padding="15dp"
android:textSize="15sp"

5. float:浮点值
属性定义:

<attr name="alpha" format="float" />

属性使用:

android:alpha="0.5"

6. integer:整型值
属性定义:

 <attr name="rowCount" format="integer" />

属性使用:

android:rowCount="3"

7. string:字符串

属性定义:

<attr name="hint" format="string" />

属性使用:

andrid:hint="hint"

8. fraction:百分数
属性定义:

<attr name="centerX" format="float|fraction" />

属性使用:

android:centerX="50%"

9. enum:枚举值
属性定义:

<attr name="orientation">
    <enum name="horizontal" value="0" />
    <enum name="vertical" value="1" />
</attr>

属性使用:

android:orientation="horizontal"

注意:枚举类型的属性在使用的过程中只能同时使用其中一个,不能 android:orientation = “horizontal|vertical"

10. flag:位或运算
属性定义:

<attr name="windowSoftInputMode">
    <flag name = "stateUnspecified" value = "0" />
    <flag name = "stateUnchanged" value = "1" />
    <flag name = "stateHidden" value = "2" />
    <flag name = "stateAlwaysHidden" value = "3" />
    <flag name = "stateVisible" value = "4" />
    <flag name = "stateAlwaysVisible" value = "5" />
    <flag name = "adjustUnspecified" value = "0x00" />
    <flag name = "adjustResize" value = "0x10" />
    <flag name = "adjustPan" value = "0x20" />
    <flag name = "adjustNothing" value = "0x30" />
</attr>

属性使用:

android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">

注意:位运算类型的属性在使用的过程中可以使用多个值

11. 混合类型:属性定义时可以指定多种类型值
属性定义:

<attr name="centerX" format="float|fraction" />

属性使用:

android:centerX="50%"
android:centerX="0.5"

以上各种类型,通过TypeArray获取时都有对应的get方法


个人总结,水平有限,如果有错误,希望大家能给留言指正!如果对您有所帮助,可以帮忙点个赞!如果转载,希望可以标明文章出处!最后,非常感谢您的阅读!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值