安卓精华教程

理解Attr,Style,Theme

2018-11-09  本文已影响4人  30cf443c3643

概念

Attr

只有在自定义View的时候会用到Attr

<declare-styleable name="ViewGroup_Layout">    
    <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>    

    <attr name="layout_height" format="dimension">        
        <enum name="fill_parent" value="-1" />        
        <enum name="match_parent" value="-1" />       
        <enum name="wrap_content" value="-2" />    
    </attr>
</declare-styleable>

layout_xxx属性的取值范围为三个枚举值 fill_parent,wrap_content 或是具体大小dp

Attr的类型,可取的值有以下类型:

获取自定义Attr

public MyView(Context context, AttributeSet attrs) {
  super(context, attrs);
  TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyStyle);
  String name = ta.getString(R.styleable.MyStyle_myName, "absfree");
   . . .
 ta.recycle()
}

而上面代码中的obtainStyledAttributes方法最终调用的是以下重载版本的方法

public final TypedArray obtainStyledAttributes (
           AttributeSet set                    //属性集
         , int[] attrs                              //想要获取的属性
         , int defStyleAttr                    //表示一个指向Style的类型为reference的Attr
        , int defStyleRes)                   //表示Style的资源ID
后两个参数都用于指定默认Style,当从attrs中找不到我们想要获取的属性时,就会使用默认Style,其中defStyleAttr的优先级高于defStyleRes

自定义Style

在res/values/styles.xml的<resources>标签内增加如下内容

<style name="MyStyle"> 
    <item name="myName">absfree</item> 
    <item name="myWeight">66</item> 
    <item name="myPhoto">@drawable/absfree</item>
</style>

在MyView类中,我们便可以通过Theme的obtainStyledAttributes获取到自定义Style的值。比如以下代码可以后去到MyStyle中的myName的值。

final Resources.Theme theme = context.getTheme();
TypedArray ta = theme.obtainStyledAttributes(attrs, R.styleable.MyStyle, 
    defStyleAttr, defStyleRes);
String name = ta.getString(R.styleable.MyStyle_myName);
ta.recycle();

使用Theme

自定义Theme的方法与自定义Style相同,也使用<style>标签。
使用只需要在AndroidManifest.xml文件的<Application>标签或是<Activity>标签中指定一个android:theme属性
注意:若想把我们自定义的Theme设置给Activity或Application,需要让我们的自定义Theme继承自一个系统Theme,否则会抛出IllegalStateException异常
另外:Style的优先级要高于Theme,如此一来我们可以先定义整个应用的整体风格样式,然后可以根据需要对局部风格样式做出个性化修改。

获取Theme中的Attr

使用?表示从Theme中查找引用的资源名,这个google叫预定义样式,用在多主题时的场景,属性值会随着主题而改变。
在xml文件中获取Theme中Attr的语法如下

?[<package_name>:][<resource_type>/]<resource_name>

若是本应用中的Attr,则可以省去<package_name>。
比如,我们向把TextView的text指定为MyStyle中的myColor,只需按如下设置:

<TextView 
    . . .
    android:textColor="?attr/myColor"/>

实战-如何管理用attr属性

  1. 建立attr_base.xml,里面放一些app公用的属性,如下声明attr的名称类型。
<attr name="config_color_pressed" format="color"/>
  1. 建立App主题theme.xml。同时在theme里面具体指定config_color_pressed的
    <style name="AppRootTheme" parent="android:Theme.Holo.Light"/>
    <style name="AppBaseTheme" parent="AppRootTheme">
             <item name="config_color_pressed">@color/config_color_pressed</item>
             ...
   </style >
  1. 建立attr.xml文件 里面放自定义View需要的属性,这个时候可以如下引用attr属性,其他地方也可以这样使用
<declare-styleable name="GroupListView">
        <item name="config_color_pressed">?attr/config_color_pressed</item>
    </declare-styleable>

这样来达到app样式统一。获取attr属性的时候 可以通过下面的方法

public static float getAttrFloatValue(Context context, int attrRes){
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attrRes, typedValue, true);
        return typedValue.getFloat();
    }

    public static int getAttrColor(Context context, int attrRes){
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attrRes, typedValue, true);
        return typedValue.data;
    }

    public static ColorStateList getAttrColorStateList(Context context, int attrRes){
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attrRes, typedValue, true);
        return ContextCompat.getColorStateList(context, typedValue.resourceId);
    }

    public static Drawable getAttrDrawable(Context context, int attrRes){
        int[] attrs = new int[] { attrRes };
        TypedArray ta = context.obtainStyledAttributes(attrs);
        Drawable drawable = ta.getDrawable(0);
        ta.recycle();
        return drawable;
    }

    public static int getAttrDimen(Context context, int attrRes){
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attrRes, typedValue, true);
        return TypedValue.complexToDimensionPixelSize(typedValue.data, QMUIDisplayHelper.getDisplayMetrics(context));
    }

具体可以参考腾讯QMUI安卓版本的代码

上一篇 下一篇

猜你喜欢

热点阅读