Android自定义属性

custom attributes and styles

自定义属性

  1. 自定义一个CustomView(extends View)类
  2. 编写values/custom_attrs.xml,在其中编写styleable和item等标签元素
  3. 在布局文件中CustomView使用自定义的属性(注意namespace)
  4. 在CustomView的构造方法中通过TypedArray获取

custom_attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomView">
        <attr name="custom_src" format="string" />
        <attr name="custom_text" format="string" />
        <attr name="custom_text_size" format="dimension" />
        <attr name="custom_text_color" format="color" />
        <attr name="custom_bg" format="reference|color" />
    </declare-styleable>
</resources>

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.example.heqiang.testsomething"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center">

<com.example.heqiang.testsomething.CustonView
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:background="#ffff0000"
    custom:custom_src="Hello"
    custom:custom_text="@string/hello_world"
    custom:custom_bg="@mipmap/ic_launcher"
    custom:custom_text_size="10sp"
    />

</LinearLayout>

MainActivity.java

public class CustonView extends View {
    private static final String TAG = "CustonView";
    public CustonView(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView);

        String src = ta.getString(R.styleable.CustomView_custom_src);
        String text = ta.getString(R.styleable.CustomView_custom_text);
        float textSize = ta.getDimension(R.styleable.CustomView_custom_text_size, 10);
        Drawable drawable = ta.getDrawable(R.styleable.CustomView_custom_bg);

        Log.e(TAG, "src = " + src + " , text = " + text + " , textSize = "+textSize);
        Log.e(TAG, "drawable = " + drawable);

        ta.recycle();
    }
}

打印结果:

E/CustonView(30405): src = Hello , text = Hello world! , textSize = 30.0
E/CustonView(30405): drawable = android.graphics.drawable.BitmapDrawable@28a01041 , text = Hello world! , textSize = 30.0

format选项

  1. boolean:布尔值
  2. color:颜色值
  3. dimension:尺寸值
  4. enum:枚举值
  5. flag:位或运算
  6. float:浮点值
  7. fraction:百分数
  8. integer:整型值
  9. reference:参考某一资源ID
  10. string:字符串

flag与enum的差别:flag表示这几个值可以做或运算,你可以叠加使用,如用bold|italic表示既加粗也变成斜体,而enum只能让你选择其中一个值。
format即使用错,只要你自定义的View中获取对应类型值也是可以的,只是在布局中写代码时,IDE就不会根据你定义的format给出相应的提示了,所以最好在自定义View时还是仔细斟酌下类型。

AttributeSet与TypedArray

AttributeSet中保存的是该View声明的所有的属性,并且外面的确可以通过它去获取(自定义的)属性。但它和通过TypedArray获取到的有什么区别呢?
看下面代码:

public class CustonView extends View {
    private static final String TAG = "CustonView";
    public CustonView(Context context, AttributeSet attrs) {
        super(context, attrs);

        int count = attrs.getAttributeCount();
        for (int i = 0; i < count; i++) {
            String attrName = attrs.getAttributeName(i);
            String attrVal = attrs.getAttributeValue(i);
            Log.e(TAG, "attrName = " + attrName + " , attrVal = " + attrVal);
        }
    }
}

结果:

E/CustonView(30405): attrName = background , attrVal = #ffff0000
E/CustonView(30405): attrName = layout_width , attrVal = 50.0dip
E/CustonView(30405): attrName = layout_height , attrVal = 50.0dip
E/CustonView(30405): attrName = custom_src , attrVal = Hello
E/CustonView(30405): attrName = custom_text , attrVal = @2131165186
E/CustonView(30405): attrName = custom_text_size , attrVal = 10.0sp
E/CustonView(30405): attrName = custom_bg , attrVal = @2130903040

看到这些打印相信大家就明白了,如果某个属性我们用的是引用,那么通过AttributeSet获取的值只是这个资源的ID,而TypedArray获得的是解析过的ID的值。因此使用TypedArray是比较方便的。

在自定义Style中加入自定义attr

values/custom_attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomView">
        <attr name="custom_src" format="string" />
        <attr name="custom_text" format="string" />
        <attr name="custom_text_size" format="dimension" />
        <attr name="custom_text_color" format="color" />
        <attr name="custom_bg" format="reference|color" />
    </declare-styleable>

    <declare-styleable name="CustomTheme">
        <attr name="customTheme" format="reference" />
    </declare-styleable>
</resources>

values/styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <!-- Customize your theme here. -->
    </style>

    <style name="CustomTheme">
        <item name="android:background">#ffff0000</item>
        <item name="custom_src">Hello</item>
        <item name="custom_text">@string/hello_world</item>
        <item name="custom_bg">@mipmap/ic_launcher</item>
        <item name="custom_text_size">10sp</item>
        <item name="custom_text_color">#ffffff00</item>
    </style>

</resources>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.example.heqiang.testsomething"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center">

<com.example.heqiang.testsomething.CustonView
    android:layout_width="50dp"
    android:layout_height="50dp"
    custom:customTheme="@style/CustomTheme"
    />

</LinearLayout>
public class CustonView extends View {
    private static final String TAG = "CustonView";
    public CustonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, R.attr.customTheme);
    }

    public CustonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //init(context, attrs, defStyleAttr);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {

        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs,
                R.styleable.CustomTheme, defStyle, 0);
        int customTheme = ta.getResourceId(R.styleable.CustomTheme_customTheme, 0);
        ta.recycle();
        Log.e(TAG, "customTheme=" + customTheme);

        //获取自定义的5个属性
        TypedArray a = context.getTheme().obtainStyledAttributes(customTheme, R.styleable.CustomView);

        String src = null;
        String text = null;
        float textSize = 0f;
        Drawable drawable = null;
        int textColor = 0;

        int N = a.getIndexCount();
        Log.e(TAG, "N="+N);
        for (int i = 0; i < N; i++) {
            int attr = a.getIndex(i);
            if(attr == R.styleable.CustomView_custom_src){
                src = a.getString(R.styleable.CustomView_custom_src);
            } else if(attr == R.styleable.CustomView_custom_text){
                text = a.getString(R.styleable.CustomView_custom_text);
            } else if(attr == R.styleable.CustomView_custom_text_size){
                textSize = a.getDimension(R.styleable.CustomView_custom_text_size, 10);
            } else if(attr == R.styleable.CustomView_custom_bg){
                drawable = a.getDrawable(R.styleable.CustomView_custom_bg);
            } else if(attr == R.styleable.CustomView_custom_text_color){
                textColor = a.getColor(R.styleable.CustomView_custom_text_color,0xffffffff);
            }
        }

        Log.e(TAG, "src = " + src + " , text = " + text + " , textSize = "+textSize);
        Log.e(TAG, "drawable = " + drawable+", textColor = "+textColor);
        a.recycle();

        //获取<item name="android:background">#ffff0000</item>
        TypedArray a1 = context.getTheme().obtainStyledAttributes(customTheme, styleable.View);
        int N1 = a.getIndexCount();
        for (int i = 0; i < N1; i++) {
            int attr = a.getIndex(i);
            if(attr == styleable.View_background){
                Log.e(TAG,"View_background attr "+attr);
                Drawable backgroundDr = a.getDrawable(attr);
                setBackground(backgroundDr);
            }
        }
        a1.recycle();
    }

    public static class styleable {
        private static final Class<?> sClassStyleable = getStyleableClass();
        public static int[] View;
        public static int View_background;
        static {
            try {
                View = (int[]) sClassStyleable.getField("View").get(null);

            } catch (Exception e) {
                Log.w(TAG, "", e);
            }

            try {
                View_background = sClassStyleable.getField("View_background").getInt(null);
            } catch (Exception e) {
                Log.w(TAG, "", e);
            }
        }

        private static Class<?> getStyleableClass() {
            try {
                Class<?> clz = Class.forName("com.android.internal.R$styleable");
                return clz;
            } catch (Exception e) {
                Log.e(TAG, "", e);
            }
            return null;
        }
    }
}

打印结果:

E/CustonView(19597): customTheme=2131034113
E/CustonView(19597): N=5
E/CustonView(19597): src = Hello , text = Hello world! , textSize = 30.0
E/CustonView(19597): drawable = android.graphics.drawable.BitmapDrawable@22bfaf1b, textColor = -256
E/CustonView(19597): View_background attr 13

UI展现的结果是和上面的一样的。

相关介绍

http://www.jianshu.com/p/dd79220b47dd

你可能感兴趣的:(android,自定义属性)