2012-06-29 94 views
22

我做复杂的布局,我使用“包括”我的自定义组件,像这样包括与自定义布局属性

<include layout="@layout/topbar"/> 

而且顶栏是这样定义的:

<?xml version="1.0" encoding="utf-8"?> 
<my.package.TopBarLayout 
... a lot of code 

现在,我想通我的自定义属性为“topbar”,像这样

<include layout="@layout/topbar" txt:trName="@string/contacts"/> 

但是我没有结果。我从that page了解到,我可以设置任何属性,但id,高度和宽度。

那么,如何传递我的自定义属性来包含,以及如何使其工作?

+0

[数据绑定不支持包括作为一个合并元素的直接孩子。](https://developer.android.com/topic/libraries/data-binding/index.html) – samosaris

回答

31

我知道这是一个古老的问题,但我遇到它,发现现在可以感谢数据绑定。

首先,您需要在项目中启用Data Binding

然后添加数据绑定到布局要包括:

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android"> 
<data> 
    <variable name="title" type="java.lang.String"/> 
</data> 
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto" 
      android:id="@+id/screen_header" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_gravity="top" 
      android:gravity="center"> 

... 

<TextView 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_centerInParent="true" 
      android:textSize="20sp" 
      android:textStyle="bold" 
      android:text="@{title}"/> 

... 

</RelativeLayout> 
</layout> 

最后,从主要布局变量传递给所包含的布局是这样的:

... 
xmlns:app="http://schemas.android.com/apk/res-auto" 
... 
<include layout="@layout/included_layout" 
      android:id="@+id/title" 
      app:title="@{@string/title}"/> 
... 
+1

它正在工作?你怎么能从XML绑定?当我尝试这个时,在包含的布局中没有文本 – Andrzej

+0

@Andrzej它适用于我,所以你必须错过一些东西,也许我忘了添加到我的答案。你可以发布你的代码,所以我试图找出什么是错的? –

+0

这确实起作用,但的确会让你依赖于数据绑定,这可能比另一个答案中描述的自定义视图方法更难调试(它更依赖编译时检查) – sapht

0

您必须在您的根xml元素中包含您的自定义名称空间。 如果你的包名com.example.test您的XML应和这样的:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:txt="http://schemas.android.com/apk/res/com.example.test" /> 

一个很好的教程:http://blog.infidian.com/2008/05/02/android-tutorial-42-passing-custom-variables-via-xml-resource-files/

+3

谢谢,但我知道它,名称空间包括在内。问题是属性没有传递到组件 –

5

不幸的是,我能贡献的唯一的事情是,我也无法在包含标签上设置自定义属性,并让它们通过包含的布局。

在这一点上它可能是不可能的。

0

我有同样的问题。在访问完此线程后,我最终使用了ViewsetTag()方法在onCreate()期间为每个View添加识别信息,然后在getTag()之后检索它。

7

我今天遇到这个问题。无论它是值得的,我认为这是一种直接的工作。不要为include标签添加属性,而是为include添加属性并为其添加属性。然后,从包装器中进行包含。让包装类实现提取属性并传递给它的单个子对象,这是包含布局的根视图。

所以,说我们宣布了一个名为SingleSettingWrapper像这样的包装一些自定义的属性 -

<declare-styleable name="SingleSettingWrapper"> 
    <attr name="labelText" format="string"/> 
</declare-styleable> 

然后,我们创建了两个自定义视图类 - 一个用于包装(SingleSettingWrapper)和一个孩子(SingleSettingChild )将包括 -

<!-- You will never end up including this wrapper - it will be pasted where ever you wanted to include. But since the bulk of the XML is in the child, that's ok --> 
<com.something.SingleSettingWrapper 
    android:id="@+id/wrapper" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    custom:labelText="@string/my_label_string"> 

    <!-- Include the child layout --> 
    <include layout="@layout/setting_single_item"/> 

</com.something.SingleSettingWrapper> 

对于孩子,我们可以把任何复杂的布局,在那里,我们想要的。我只是把一些基本的东西,但实际上可以包括任何 -

<com.something.SingleSettingItem 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="vertical"> 
    <RelativeLayout > 
     <!-- add whatever custom stuff here --> 
     <!-- in this example there would be a text view for the label and maybe a bunch of other stuff --> 
     <!-- blah blah blah --> 
    </RelativeLayout> 
</com.something.SingleSettingItem> 

对于包装(这是关键),我们看到在构造函数中我们所有的自定义属性。然后,我们重写onViewAdded()并将这些自定义属性传递给我们的孩子。

public class SingleSettingWrapper extends FrameLayout 
{ 
    private String mLabel; 

    public SingleSettingWrapper(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 

     TypedArray a = context.getTheme().obtainStyledAttributes(attrs, 
                  R.styleable.SingleSettingWrapper, 
                  0, 0); 

     mLabel = a.getString(R.styleable.SingleSettingWrapper_labelText); 
     a.recycle(); 
    } 

    public void onViewAdded(View child) 
    { 
     super.onViewAdded(child); 
     if (!(child instanceof SingleSettingItem)) 
      return; 

     ((TextView)child.findViewById(R.id.setting_single_label)).setText(mLabel); 
     /* 
     Or, alternatively, call a custom method on the child implementation - 
     ((SingleSettingItem)child)setLabel(mLabel); 
     */ 
    } 
} 

可选,可以实现孩子太并将其从包装接收消息和修改本身(而不是有包装修改的孩子就像我上面一样)。

public class SingleSettingItem extends LinearLayout 
{ 
    public SingleSettingItem(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    public void setLabel(String l) 
    { 
     // set the string into the resource here if desired, for example 
    } 
} 

在这一天结束时,每个地方你想<include>的XML文件的布局将包含约7 XML的线包装+包括的,而不是单一的包括你想要的,但如果包含视图包含数百行你仍然更好。例如 -

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:custom="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="vertical" > 

    <!-- this is the beginning of your custom attribute include --> 
    <com.something.SingleSettingWrapper 
     android:id="@+id/my_wrapper" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     custom:labelText="@string/auto_lock_heading"> 
     <include layout="@layout/setting_single_item"/> 
    </com.something.SingleSettingWrapper> 
    <!-- this is the end of your custom attribute include --> 
</LinearLayout> 

实际上,这似乎工作得很好,而且设置起来相对简单。我希望它能帮助别人。

+0

有点太复杂,将视图包装到视图中 –