【问题标题】:Custom XML attributes without custom View in Fragment在 Fragment 中没有自定义视图的自定义 XML 属性
【发布时间】:2013-01-25 21:01:22
【问题描述】:

我正在尝试在现有视图中添加自定义 XML 属性

将它们添加到自定义视图并不是什么大问题,但我不知道如何在“基本”视图中访问这些属性(例如 TextView、LinearLayout、ImageView ...)

当涉及片段和/或库项目时,这会更加困难

到目前为止,这是我的代码

海关属性定义和 XML(attrs.xml 和布局):

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="StarWars">
    <attr name="jedi" format="string" />
    <attr name="rank" format="string" />
</declare-styleable>

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:sw="http://schemas.android.com/apk/res-auto"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    android:gravity="center_horizontal"
    sw:jedi="Obiwan" />

<TextView
    android:id="@+id/rank"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    android:gravity="center_horizontal"
    sw:rank="Master" />

由于我在 Fragment 上对此进行了膨胀(所以没有使用 attrs arg 的 onCreate !),尝试获取 2 sw 自定义属性的唯一方法是:

  1. 在onCreateView中为Fragment LayoutInflater设置一个自定义的LayoutInflater.Factory

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      super.onCreateView(inflater, container, savedInstanceState);
    
      LayoutInflater layoutInflater = inflater.cloneInContext(inflater.getContext());
      layoutInflater.setFactory(new StarWarsLayoutFactory());
    
      View fragmentView = layoutInflater.inflate(R.layout.jedi, container, false);
      ((TextView) fragmentView.findViewById(android.R.id.jedi)).setText("Yep");
    
      return fragmentView;
    }
    
  2. 尝试获取自定义 LayoutInflater.Factory 上的自定义属性:

    public class StarWarsLayoutFactory implements Factory {
      @Override
      public View onCreateView(String name, Context context, AttributeSet attrs) {
                  *** What to do here ? ***
    
          return null;
      }
    }
    

有人有过这样的问题吗?

我在这里缺少什么?

提前谢谢!

【问题讨论】:

    标签: android android-fragments android-view android-xml android-custom-attributes


    【解决方案1】:

    我终于做到了:)

    您必须像我在 OP 上所做的那样创建一个新的 LayoutInflater.Factory,但由于工厂用于所有膨胀的布局视图,并且您必须在 Factory.onCreateView 上返回 null(让 Android 处理膨胀)您必须在某处缓存您的自定义 XML 属性

    所以这里是解决方案:

    • 你的布局 XML View 必须有和 android:id

    • 创建将保留您的自定义属性的类:

        public class AttributeParser {
    
        private AttributeParserFactory mFactory;
        private Map<Integer, HashMap<Integer, String>> mAttributeList;
    
        private class AttributeParserFactory implements LayoutInflater.Factory{
            @Override
            public View onCreateView(String name, Context context, AttributeSet attrs) {
                String id = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "id");
    
                if(id != null){
                    // String with the reference character "@", so we strip it to keep only the reference
                    id = id.replace("@", "");
    
                    TypedArray libraryStyledAttributeList = context.obtainStyledAttributes(attrs, R.styleable.NewsHubLibrary);
                    HashMap<Integer, String> libraryViewAttribute = new HashMap<Integer, String>();
                    int i = 0;
    
                    for(int attribute : R.styleable.NewsHubLibrary){
                        String attributeValue = libraryStyledAttributeList.getString(i);
    
                        if(attributeValue != null)
                            libraryViewAttribute.put(attribute, attributeValue);
    
                        i++;
                    }
    
                    if(!libraryViewAttribute.isEmpty())
                        mAttributeList.put(Integer.valueOf(id), libraryViewAttribute);
    
                    libraryStyledAttributeList.recycle();
                }
    
                return null;
            }
    
        }
    
        public AttributeParser(){
            mAttributeList = new HashMap<Integer, HashMap<Integer, String>>();
            mFactory = new AttributeParserFactory();
        }
    
        public void clear() {
            mAttributeList.clear();
        }
    
        public LayoutInflater getLayoutInflater(LayoutInflater inflater) {
            clear();
            LayoutInflater layoutInflater = inflater.cloneInContext(inflater.getContext());
            layoutInflater.setFactory(mFactory);
    
            return layoutInflater;
        }
    
        public void setFactory(LayoutInflater inflater){
            inflater.cloneInContext(inflater.getContext()).setFactory(mFactory);
        }
    
        public void setViewAttribute(Activity activity) {
            for(Entry<Integer, HashMap<Integer, String>> attribute : mAttributeList.entrySet())
                if(activity.findViewById((Integer) attribute.getKey()) != null)
                    activity.findViewById((Integer) attribute.getKey()).setTag(attribute.getValue());
    
        }
    
        public void setViewAttribute(View view) {
            for(Entry<Integer, HashMap<Integer, String>> attribute : mAttributeList.entrySet())
                if(view.findViewById((Integer) attribute.getKey()) != null)
                    view.findViewById((Integer) attribute.getKey()).setTag(attribute.getValue());
        }
    
        public Map<Integer, HashMap<Integer, String>> getAttributeList() {
            return mAttributeList;
        }
    
        public void setAttributeList(Map<Integer, HashMap<Integer, String>> attributeList) {
            this.mAttributeList = attributeList;
        }
        }
    
    • 当您使用 AttributeParser 时,您的自定义属性将存储在每个 View 标记中:

        LayoutInflater layoutInflater = mAttributeParser.getLayoutInflater(inflater);
        View view = layoutInflater.inflate(R.layout.jedi, null);
        mAttributeParser.setViewAttribute(view);
    

    【讨论】:

    • 你也可以分享你的 attrs.xml 吗?
    • 它在 support-v4:22.0.0 上运行良好,但在更高版本(例如 support-v4:23.0.1)上没有调用 onCreateView 并且 mAttributeList 大小为 0。为什么?
    • 我真的不知道,这个解决方法是很久以前的了。检查 Google 是否改变了 LayoutInflater 的工作方式
    • 应该是Factory2
    【解决方案2】:

    标准TextView 等不会访问这些属性。您可以扩展它并提供包括读取这些自定义属性的功能。

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StarWars, 0, 0);
    
    String jedi = a.getText(R.styleable.StarWars_jedi);
    String rank = a.getText(R.styleable.StarWars_rank);
    
    a.recycle();
    

    记得最后总是打电话给recycle()。

    【讨论】:

    • 是的,我知道如何使用扩展视图来做到这一点,但我需要为所有视图实现这一点,无论是否扩展
    猜你喜欢
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 2015-09-23
    相关资源
    最近更新 更多