Android 包括具有自定义属性的布局

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11265258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:34:56  来源:igfitidea点击:

Include layout with custom attributes

androidandroid-layout

提问by Roman Truba

I making complex layout and I using "include" for my custom component, like this

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

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

And topbar defined like this:

顶栏定义如下:

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

Now, I wanna pass my custom defined attributes to "topbar" like this

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

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

But I have no result. I understood from that pagethat I can set no attributes, but id, height and width.

但我没有结果。我从那个页面了解到,我不能设置任何属性,只能设置 id、高度和宽度。

So, how can I pass my custom defined attributes to include, and how can I make it work?

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

回答by Sir Codesalot

I know this is an old question but I came across it and found that it is now possible thanks to Data Binding.

我知道这是一个老问题,但我遇到了它并发现现在可以通过数据绑定来实现。

First you need to enable Data Bindingin your project.

首先,您需要在项目中启用数据绑定

Then add data binding to the layout you want to include:

然后将数据绑定添加到要包含的布局:

<?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>

Finally, pass the variable from the main layout to the included layout like this:

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

<?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>

回答by Jason

It's not possible to attributes other than layout params, visibility or ID on an include tag. This includes custom attributes.

除了布局参数、可见性或 ID 之外,不能在包含标签上设置属性。这包括自定义属性。

You can verify this by looking at the source of the LayoutInflater.parseInclude method, around line 705: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/view/LayoutInflater.java#640

您可以通过查看 LayoutInflater.parseInclude 方法的源代码来验证这一点,大约在第 705 行:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1 .1/android/view/LayoutInflater.java#640

The inflater only applies the ID and visibility attributes to the included layout.

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

回答by tpankake

I ran into this issue today. For whatever it is worth, I think there is a straight-forward work around. Instead of adding attributes to the include tag, create a custom wrapper view for the include and add attributes to that. Then, do the include from the wrapper. Have the wrapper class implementation extract the attributes and pass along to its single child, which is the root view of the include layout.

我今天遇到了这个问题。不管它值多少钱,我认为有一个直接的解决方法。不是向包含标记添加属性,而是为包含创建自定义包装视图并为其添加属性。然后,从包装器中进行包含。让包装类实现提取属性并将其传递给它的单个子项,即包含布局的根视图。

So, say we declare some custom attributes for a wrapper called SingleSettingWrapper like this -

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

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

Then, we create two custom view classes - one for the wrapper (SingleSettingWrapper) and one for the child (SingleSettingChild) that will be included -

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

For the child, we can put whatever complex layout in there that we want. I'll just put something basic, but really you can include whatever -

对于孩子,我们可以在其中放置任何我们想要的复杂布局。我只会放一些基本的东西,但实际上你可以包括任何东西 -

<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>

For the wrapper (this is the key), we read all of our custom attributes in the constructor. Then, we override onViewAdded() and pass those custom attributes to our child.

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

Optionally, you can implement the child too and have it receive messages from the wrapper and modify itself (instead of having the wrapper modify the child as I did above).

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

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
    }
}

At the end of the day, each of the XML files where you wanted to <include>your layout will contain about 7 lines of XML for the wrapper+include instead of the single include that you wanted, but if the included view contains hundreds of lines you're still way better off. 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>

In practice, this seems to work pretty well and is relatively simple to set up. I hope it helps someone.

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

回答by Jay Bobzin

Unfortunately, the only thing I can contribute is that I was also unable to set custom attributes on an include tag, and have them pass through to the included layout.

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

It may well not be possible at this point.

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

回答by pmitchell

回答by gotube

I had the same question. After visiting this thread, I ended up using View's setTag()methods to attach identifying information to each Viewduring onCreate(), and then getTag()methods to retrieve it later on.

我有同样的问题。访问此线程后,我最终使用ViewsetTag()方法将识别信息附加到每个View期间onCreate(),然后使用getTag()方法稍后检索它。

回答by Stefano Ortisi

You have to include in your root xml element your custom namespace. If your package name is com.example.test your xml shold be something like this:

您必须在根 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" />

A nice tutorial is: http://blog.infidian.com/2008/05/02/android-tutorial-42-passing-custom-variables-via-xml-resource-files/

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