zoukankan      html  css  js  c++  java
  • android中如何获取xml界面里的非自定义属性

    获取自定义属性大家都很熟悉了,就不多说了(定义declare-styleable,context.obtainStyledAttributes巴拉巴拉...)

    下面我们说一下怎么获取非自定义的属性,比如android:entries,android:gravity等等,上面的方式照着套是行不通了,因为你无法取得android.R.styleable里面的东西,下面是我试出来的几种方法:

    1. 遍历AttributeSet,基本可以把所有xml里的属性取出来,但是有一点,取出来的值要能使用,需要经过一定处理,具体代码如下:

     1         //find entries
     2         int count = attrs.getAttributeCount();
     3         for (int i = 0; i < count; i++) {
     4             if ("entries".equals(attrs.getAttributeName(i))) {
     5                 int resid = attrs.getAttributeResourceValue(i, 0);
     6                 if (resid > 0) {
     7                     String[] entries = context.getResources().getStringArray(resid);
     8                     if (entries != null) {
     9                         //get gravity
    10                         int g = -1;
    11                         for (int j = 0; j < count; j++) {
    12                             if ("gravity".equals(attrs.getAttributeName(j))) {
    13                                 g = j;
    14                                 break;
    15                             }
    16                         }
    17                         final int gravity = attrs.getAttributeIntValue(g, Gravity.CENTER);
    18                         //create adapter
    19                         ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context, R.layout.item_spinner_top, R.id.text, entries) {
    20                             @Override
    21                             public View getView(int position, View convertView, ViewGroup parent) {
    22                                 View view = super.getView(position, convertView, parent);
    23                                 TextView text = ButterKnife.findById(view, R.id.text);
    24                                 text.setTextColor(textColor);
    25                                 text.setTextSize(DimenUtils.px2dp(textSize));
    26                                 text.setGravity(gravity);
    27                                 return view;
    28                             }
    29 
    30                             @Override
    31                             public View getDropDownView(int position, View convertView, ViewGroup parent) {
    32                                 View dropDownView = super.getDropDownView(position, convertView, parent);
    33                                 TextView text = ButterKnife.findById(dropDownView, R.id.text);
    34                                 text.setTextColor(dropdownTextColor);
    35                                 text.setTextSize(DimenUtils.px2dp(textSize));
    36                                 text.setGravity(gravity);
    37                                 return dropDownView;
    38                             }
    39                         };
    40                         adapter.setDropDownViewResource(R.layout.item_spinner_dropdown);
    41                         setAdapter(adapter);
    42                     }
    43                 }
    44                 break;
    45             }
    46         }

    2. 还是使用context.obtainStyledAttributes,数组可以从android.R.attr里面取(不需要styleable了),处理起来跟以前差不多,很好用,推荐

        private static final int[] RX_SPINNER_OVERRIDE_ATTRS = {
                android.R.attr.entries,
                android.R.attr.gravity
        };
    
            a = context.obtainStyledAttributes(attrs,RX_SPINNER_OVERRIDE_ATTRS);
            if (a.hasValue(0)){
                CharSequence[] entries = a.getTextArray(0);
                final int gravity = a.getInt(1,Gravity.CENTER);
                //create adapter
                ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context, R.layout.item_spinner_top, R.id.text, entries) {
                    @Override
                    public View getView(int position, View convertView, ViewGroup parent) {
                        View view = super.getView(position, convertView, parent);
                        TextView text = ButterKnife.findById(view, R.id.text);
                        text.setTextColor(textColor);
                        text.setTextSize(DimenUtils.px2dp(textSize));
                        text.setGravity(gravity);
                        return view;
                    }
    
                    @Override
                    public View getDropDownView(int position, View convertView, ViewGroup parent) {
                        View dropDownView = super.getDropDownView(position, convertView, parent);
                        TextView text = ButterKnife.findById(dropDownView, R.id.text);
                        text.setTextColor(dropdownTextColor);
                        text.setTextSize(DimenUtils.px2dp(textSize));
                        text.setGravity(gravity);
                        return dropDownView;
                    }
                };
                adapter.setDropDownViewResource(R.layout.item_spinner_dropdown);
                setAdapter(adapter);
            }
            a.recycle();

     在使用中无意发现另外一个问题,tint相关属性即使设置了,在5.0以下也是拿不到的,究其原因应该是这个是api level 21才引入的,低于这个的机器上被忽略了,那么要同时兼容高低版本的话,可以使用v7包里的tint属性,android.support.v7.appcompact.R.attr.backgroundTint等,使用的时候就不要用android:backgroundTint了,改用app:backgroundTint即可。

    9月17日更新

         抱歉,上面的代码没有经过详细测试,实际上只能拿到entries的值,拿不到gravity的值,我也很奇怪,百思不得其解,照理说应该是同样的模式,追踪代码追到最后是一个native方法...

         然后我去stackoverflow上提了问题(http://stackoverflow.com/questions/32602982/can-get-entries-but-not-gravity/),尝试让国外大神帮我看下,然而并没有人回答,今天花了一天时间找了半天原因,总算是找到了,记录一下。

         gravity不能获取的原因是,v7包里,它被重新定义了!

        

    <declare-styleable name="Spinner"><attr format="reference" name="prompt"/><attr format="enum" name="spinnerMode"><enum name="dialog" value="0"/><enum name="dropdown" value="1"/></attr><attr name="android:dropDownSelector"/><attr name="android:popupBackground"/><attr name="android:dropDownVerticalOffset"/><attr name="android:dropDownHorizontalOffset"/><attr name="android:dropDownWidth"/><attr format="reference" name="popupPromptView"/><attr name="android:gravity"/><attr format="boolean" name="disableChildrenWhenDisabled"/><attr name="android:background"/></declare-styleable>

        注意里面重新定义了一些属性(比如<attr name="android:gravity"/>),可能由于这个原因,上面的获取方法失效了.

        解决办法也很简单,从v7包里取就可以了!v7包是可以访问styleable的,这样就能使用常规方法来取了!

        

    1     a = context.obtainStyledAttributes(attrs,android.support.v7.appcompat.R.styleable.Spinner);
    2     final int gravity = a.getInt(android.support.v7.appcompat.R.styleable.Spinner_android_gravity,Gravity.CENTER);
    3     a.recycle();

        ok,测试通过!

        更进一步

        通过v7兼容包里的写法,我们知道了,通过定义<attr name="android:gravity"/>是可以重定义android原生属性的(不知道重定义在这里用得准不准确,反正是这么个意思,大家理解就可以了)

        那么假如你有个自定义组件,想使用类似android:gravity,android:xxx之类的属性,实现一些其他功能或者可定义性,那么完全可以自己在attr里面定义,只需要写上name就行了,不需要设置format,还有枚举什么的一大堆,全部是自动继承的!

        然后xml里就还是跟以前一样设置,android:xxx=yyy,java里面可以跟自定义属性一样取,简单方便!下面上个例子

        

    1     <declare-styleable name="RxSpinner">
    2         <attr name="text_size" format="dimension"/>
    3         <attr name="text_color" format="color" />
    4         <attr name="dropdown_text_color" format="color"/>
    5         <attr name="android:gravity" />
    6         <attr name="android:entries" />
    7     </declare-styleable>
    1         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RxSpinner);
    2         final int textColor = a.getColor(R.styleable.RxSpinner_text_color, context.getResources().getColor(R.color.gray_dark));
    3         final float textSize = a.getDimension(R.styleable.RxSpinner_text_size, context.getResources().getDimension(R.dimen.text_normal));
    4         final int dropdownTextColor = a.getColor(R.styleable.RxSpinner_dropdown_text_color, context.getResources().getColor(R.color.gray_dark));
    5         final int gravity = a.getInt(R.styleable.RxSpinner_android_gravity,Gravity.CENTER);     //get android:gravity
    6         final CharSequence[] entries = a.getTextArray(R.styleable.RxSpinner_android_entries);   //get android:entries
    7         a.recycle();

         怎么样,是不是很好用,蛤蛤。

         折腾这么多天,总算弄清楚了,找到了一种简洁的写法。其实一开始我就在想,有没有什么办法,让自定义组件的属性直接继承,后面走了不少弯路,看了v7源码才知道,可以这么写,原来就是加一个android命名空间的事,源码还是很有参考价值的。

  • 相关阅读:
    css水平垂直居中问题
    关系型数据库四大特性
    C++读取csv文件&&收获到的知识
    恒生面试记录
    SQL数据库操作命令
    安防产品知识记录
    学会求助(带着自己的理解去和别人探讨解决方案),处理问题责任清晰,如果不清楚可以问主管.
    一个简单又不简单的socket例子
    C++面试题总结
    大华电话面试
  • 原文地址:https://www.cnblogs.com/DarkMaster/p/4811057.html
Copyright © 2011-2022 走看看