Android自定义属性深入理解

版权声明:本文为博主原创文章,可以随意转载,但是必须在开头标明出处。 https://blog.csdn.net/qq_29951983/article/details/80219746

上周看过这样一段代码

TypedArray sa = obtainStyledAttributes(null,
                com.android.internal.R.styleable.PreferenceActivity,
                com.android.internal.R.attr.preferenceActivityStyle,
                0);

发现特别神奇,之前都是用前两个参数在自定义View中进行应用,发现还有四个参数的写法,于是就查看了一下Android系统控件里面,是如何应用的。

系统如何自定义属性

这里就拿TextView举例吧:

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

    public TextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.textViewStyle);
    }

    public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    @SuppressWarnings("deprecation")
    public TextView(
            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

我介绍的几个目录你可能一开始看的时候感觉没啥关联,但是你往后看就知道了,学习技术要有耐心。
1. TextView自定义的属性所在目录

/***/***/SDK/platforms/android-22/data/res/values/attrs.xml

<declare-styleable name="TextView">
        <!-- Determines the minimum type that getText() will return.
             The default is "normal".
             Note that EditText and LogTextBox always return Editable,
             even if you specify something less powerful here. -->
        <attr name="bufferType">
            <!-- Can return any CharSequence, possibly a
             Spanned one if the source text was Spanned. -->
            <enum name="normal" value="0" />
            <!-- Can only return Spannable. -->
            <enum name="spannable" value="1" />
            <!-- Can only return Spannable and Editable. -->
            <enum name="editable" value="2" />
        </attr>
        <!-- Text to display. -->
        <attr name="text" format="string" localization="suggested" />
        <!-- Hint text to display when the text is empty. -->
        <attr name="hint" format="string" />
        <!-- Text color. -->
        <attr name="textColor" />
        <!-- Color of the text selection highlight. -->
        <attr name="textColorHighlight" />
        <!-- Color of the hint text. -->
        <attr name="textColorHint" />
        <!-- Base text color, typeface, size, and style. -->
        <attr name="textAppearance" />
        <!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
        <attr name="textSize" />
        <!-- Sets the horizontal scaling factor for the text. -->
        <attr name="textScaleX" format="float" />
        <!-- Typeface (normal, sans, serif, monospace) for the text. -->
        <attr name="typeface" />
        <!-- Style (bold, italic, bolditalic) for the text. -->
        <attr name="textStyle" />
        <!-- Font family (named by string) for the text. -->
        <attr name="fontFamily" />
        <!-- Text color for links. -->
        <attr name="textColorLink" />
        <!-- Makes the cursor visible (the default) or invisible. -->
        <attr name="cursorVisible" format="boolean" />
        <!-- Makes the  be at most this many lines tall.

        When used on an editable text, the <code>inputType</code> attribute's value must be
        combined with the <code>textMultiLine</code> flag for the maxLines attribute to apply. -->
        <attr name="maxLines" format="integer" min="0" />
        <!-- Makes the TextView be at most this many pixels tall. -->
        <attr name="maxHeight" />
        <!-- Makes the TextView be exactly this many lines tall. -->
        <attr name="lines" format="integer" min="0" />
        <!-- Makes the TextView be exactly this many pixels tall.
             You could get the same effect by specifying this number in the
             layout parameters. -->
        <attr name="height" format="dimension" />
        <!-- Makes the TextView be at least this many lines tall.

        When used on an editable text, the <code>inputType</code> attribute's value must be
        combined with the <code>textMultiLine</code> flag for the minLines attribute to apply. -->
        <attr name="minLines" format="integer" min="0" />
        <!-- Makes the TextView be at least this many pixels tall. -->
        <attr name="minHeight" />
        <!-- Makes the TextView be at most this many ems wide. -->

这里跟我们平时自定义属性是完全一样的。
2. textViewStyle
<attr name="textViewStyle" format="reference" />
这个参数的定义也同样是在attrs.xml里面进行定义的,你可以自己搜索下
3. themes
/***/***/SDK/platforms/android-22/data/res/values/themes.xml
这个是系统的theme文件,一般我们自己定义一个theme的时候都会采用继承,有两种写法。
a:通过parent继承
类似这种
<style name="Theme.AppCompat.Light.DarkActionBar" parent="Base.Theme.AppCompat.Light.DarkActionBar"/>
前面是子类名字,后面是父类名字
b:通过 父类.子类的方式
<style name="Theme.Light"> Theme是父类,Light是自己定义的子类。
在manifest文件中我的applicationandroid:theme="@style/AppTheme"

 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="MyViewStyle">@style/buzhidao</item>
    </style>

最后的结构是这样的:
Theme
–Theme.Light
—android:Theme.Holo.Light
—-Platform.AppCompat.Light
—–Base.V7.Theme.AppCompat.Light
——Base.Theme.AppCompat.Light
——-Base.Theme.AppCompat.Light.DarkActionBar
——–Theme.AppCompat.Light.DarkActionBar
———AppTheme
而在themes.xml这个文件的跟节点就是<style name="Theme">
在它的里面定义了
<item name="textViewStyle">@style/Widget.TextView</item>
也就是跟刚才attrs.xml里面定义的textViewStyle的name一样,但是其值指向的styles.xml文件。
4. styles.xml目录
/***/***/SDK/platforms/android-22/data/res/values/styles.xml

<style name="Widget.TextView">
        <item name="textAppearance">?attr/textAppearanceSmall</item>
        <item name="textSelectHandleLeft">?attr/textSelectHandleLeft</item>
        <item name="textSelectHandleRight">?attr/textSelectHandleRight</item>
        <item name="textSelectHandle">?attr/textSelectHandle</item>
        <item name="textEditPasteWindowLayout">?attr/textEditPasteWindowLayout</item>
        <item name="textEditNoPasteWindowLayout">?attr/textEditNoPasteWindowLayout</item>
        <item name="textEditSidePasteWindowLayout">?attr/textEditSidePasteWindowLayout</item>
        <item name="textEditSideNoPasteWindowLayout">?attr/textEditSideNoPasteWindowLayout</item>
        <item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
        <item name="textCursorDrawable">?attr/textCursorDrawable</item>
    </style>

这里面主要是给自定义的属性设置默认的属性值。
通过上面我们就已经了解了系统自定义属性的步骤,然后下面我们自己模仿系统去写一个

例子

a:先定义attr

<resources>
    <declare-styleable name="yaoyan">
        <attr name="jingzhuiteng" format="boolean"></attr>
        <attr name="msg" format="string"></attr>
        <attr name="shuaibushuai" format="dimension"></attr>
    </declare-styleable>
</resources>

b:在attr中声明View的style名字
<attr name="MyViewStyle" format="reference"></attr>
a和b结合之后

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="yaoyan">
        <attr name="jingzhuiteng" format="boolean"></attr>
        <attr name="msg" format="string"></attr>
        <attr name="shuaibushuai" format="dimension"></attr>
    </declare-styleable>

    <attr name="MyViewStyle" format="reference"></attr>
</resources>

c:在子类AppTheme(根据你项目实际情况)中添加你自己声明的style
<item name="MyViewStyle">@style/buzhidao</item>
d:为你自己定义的style设置默认值

<style name="buzhidao">
        <item name="jingzhuiteng">true</item>
        <item name="msg">我在广东已经嫖到失联</item>
        <item name="shuaibushuai">@dimen/title_textview_size</item>
        <item name="android:background">#000000</item>
    </style>

c和d结合之后

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="MyViewStyle">@style/buzhidao</item>
    </style>

    <style name="buzhidao">
        <item name="jingzhuiteng">true</item>
        <item name="msg">我在广东已经嫖到失联</item>
        <item name="shuaibushuai">@dimen/title_textview_size</item>
        <item name="android:background">#000000</item>
    </style>

</resources>

自定义View

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.attr.MyViewStyle);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);

    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.yaoyan, defStyleAttr, defStyleRes);
        String string = a.getString(R.styleable.yaoyan_msg);
        System.out.println("string = " + string);
        float dimension = a.getDimension(R.styleable.yaoyan_shuaibushuai, 1);
        System.out.println("dimension = " + dimension);

    }

}

结果

05-06 23:04:38.955 3082-3082/com.example.customattr I/System.out: string = 我在广东已经嫖到失联
    dimension = 30.0

当然了,你也可以这么写

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="yaoyan">
        <attr name="jingzhuiteng" format="boolean"></attr>
        <attr name="msg" format="string"></attr>
        <attr name="shuaibushuai" format="dimension"></attr>
    </declare-styleable>
    //删掉一行
</resources>
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        //删掉一行
    </style>

    <style name="buzhidao">
        <item name="jingzhuiteng">true</item>
        <item name="msg">我在广东已经嫖到失联</item>
        <item name="shuaibushuai">@dimen/title_textview_size</item>
        <item name="android:background">#000000</item>
    </style>

</resources>

都删掉

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        //注意对比
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
       //注意对比
        this(context, attrs, defStyleAttr, R.style.buzhidao);

    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.yaoyan, defStyleAttr, defStyleRes);
        String string = a.getString(R.styleable.yaoyan_msg);
        System.out.println("string = " + string);
        float dimension = a.getDimension(R.styleable.yaoyan_shuaibushuai, 1);
        System.out.println("dimension = " + dimension); 
    } . 

}

第三个参数是默认的style属性,可以写0,代表没有,第四个是默认的style资源,这样改完和之前运行一样。

05-06 23:13:28.167 6732-6732/com.example.customattr I/System.out: string 改后= 我在广东已经嫖到失联
    dimension 改后= 30.0

微信公众号
这里写图片描述
QQ群:365473065
代码地址

猜你喜欢

转载自blog.csdn.net/qq_29951983/article/details/80219746