包含具有自定义属性的布局

Rom*_*uba 42 android android-layout

我制作复杂的布局,并使用"include"作为我的自定义组件,就像这样

<include layout="@layout/topbar"/>
Run Code Online (Sandbox Code Playgroud)

并且topbar定义如下:

<?xml version="1.0" encoding="utf-8"?>
<my.package.TopBarLayout
 ... a lot of code
Run Code Online (Sandbox Code Playgroud)

现在,我想将我的自定义属性传递给"topbar",就像这样

<include layout="@layout/topbar" txt:trName="@string/contacts"/>
Run Code Online (Sandbox Code Playgroud)

但我没有结果.我从那个页面了解到我不能设置任何属性,而是id,height和width.

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

Sir*_*lot 68

我知道这是一个古老的问题但是我发现它现在可以归功于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>
Run Code Online (Sandbox Code Playgroud)

最后,将变量从主布局传递到包含的布局,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
    ...
</data>    
...
xmlns:app="http://schemas.android.com/apk/res-auto"
...
<include layout="@layout/included_layout"
            android:id="@+id/title"
            app:title="@{@string/title}"/>
...
</layout>
Run Code Online (Sandbox Code Playgroud)

  • 这是工作?你怎么能从xml绑定?当我尝试这个时,包含的布局中没有文字 (5认同)
  • 为了使它起作用,您需要记住必须启用数据绑定,并且必须通过DataBindingUtil.inflate对其进行膨胀,而不仅仅是常规视图膨胀。但是,可以。 (5认同)
  • @DanChaltiel如果你想要硬编码字符串,你可以这样做.`应用程序:标题= '@ { "foo" 的}'` (2认同)

Jas*_*son 9

除了包含标记上的布局参数,可见性或ID之外,其他属性是不可能的.这包括自定义属性.

您可以通过查看第705行附近的LayoutInflater.parseInclude方法的来源来验证这一点:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1 0.1 /机器人/视图/ LayoutInflater.java#640

inflater仅将ID和可见性属性应用于包含的布局.


tpa*_*ake 9

我今天遇到了这个问题.无论它有什么价值,我认为有一个直截了当的工作.不是为include标记添加属性,而是为include创建自定义包装器视图,并为其添加属性.然后,从包装器中执行include.让包装器类实现提取属性并传递给它的单个子节点,这是包含布局的根视图.

所以,假设我们为一个名为SingleSettingWrapper的包装器声明了一些自定义属性,如下所示 -

<declare-styleable name="SingleSettingWrapper">
    <attr name="labelText" format="string"/>
</declare-styleable>
Run Code Online (Sandbox Code Playgroud)

然后,我们创建两个自定义视图类 - 一个用于包装器(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>
Run Code Online (Sandbox Code Playgroud)

对于孩子,我们可以在那里放置任何我们想要的复杂布局.我会把一些基本的东西,但你真的可以包括任何东西 -

<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>
Run Code Online (Sandbox Code Playgroud)

对于包装器(这是键),我们在构造函数中读取所有自定义属性.然后,我们覆盖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);
        */
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您也可以实现子进程并让它从包装器接收消息并自行修改(而不是像上面那样让包装器修改子进程).

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
    }
}
Run Code Online (Sandbox Code Playgroud)

在一天结束时,您希望<include>布局的每个XML文件将包含大约7行XML for wrapper + include而不是您想要的单个包含,但如果包含的视图包含数百行,那么还是会更好.例如 -

<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>
Run Code Online (Sandbox Code Playgroud)

在实践中,这似乎工作得很好,并且设置起来相对简单.我希望它对某人有帮助.


Jay*_*zin 7

不幸的是,我唯一能做的就是我也无法在include标签上设置自定义属性,并将它们传递给包含的布局.

在这一点上可能是不可能的.