54

include複雑なレイアウトを作成していて、次のようにカスタムコンポーネントにタグを使用したいと思います。

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

topbarレイアウトにはカスタムルートコンポーネントがあり、レイアウトxmlファイルでは次のように定義されています。

<my.package.TopBarLayout
 ... a lot of code

次に、カスタム定義の属性を次のように「トップバー」に渡します。

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

次に、これらのカスタム属性の値をカスタムコンポーネントコードまたは理想的にはxmlで取得します。

残念ながら、txt:trName属性の値を取得してレイアウトに反映させることがtopbarできず、コードで何も受信しません。そのドキュメントページから正しく理解していれば、、、、およびを介しincludeて使用されるレイアウトの属性を設定することはできません。idheightwidth

だから私の質問は、カスタム定義された属性を経由で追加されるレイアウトに渡すにはどうすればよいincludeですか?

4

7 に答える 7

83

これは古い質問であることは知っていますが、私はそれに出くわし、Data Binding のおかげで今では可能であることがわかりました。

まず、プロジェクトでデータ バインディングを有効にする必要があります。( の場合は のDataBindingUtil.inflate代わりに) を使用して動作させます。setContentViewActivity

次に、含めるレイアウトにデータ バインディングを追加します。

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

最後に、変数をメイン レイアウトからインクルード レイアウトに次のように渡します。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        ...
    </data>
    ...
    <include layout="@layout/included_layout"
        android:id="@+id/title"
        app:title="@{@string/title}"/>
    ...
</layout>
于 2016-07-31T06:33:23.707 に答える
10

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

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

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

于 2013-12-10T18:35:53.387 に答える
9

今日、この問題に遭遇しました。それが何であれ、私は簡単な回避策があると思います。include タグに属性を追加する代わりに、include のカスタム ラッパー ビューを作成し、それに属性を追加します。次に、ラッパーからインクルードを実行します。ラッパー クラスの実装で属性を抽出し、インクルード レイアウトのルート ビューである単一の子に渡します。

たとえば、SingleSettingWrapper というラッパーのカスタム属性を次のように宣言するとします。

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

次に、2 つのカスタム ビュー クラスを作成します。

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

結局のところ、レイアウトしたい XML ファイルのそれぞれには、<include>必要な単一のインクルードではなく、ラッパー + インクルードの約 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>

実際には、これはかなりうまく機能しているようで、設定も比較的簡単です。誰かの役に立てば幸いです。

于 2016-04-12T21:00:46.250 に答える
8

残念ながら、私が貢献できる唯一のことは、インクルード タグにカスタム属性を設定できず、それらをインクルード レイアウトに渡すことができなかったことです。

現時点では無理かもしれません。

于 2013-01-11T06:49:49.340 に答える
1

カスタム属性、または API ページ (少なくとも 5.0.0 まで) に記載されているもの以外の属性では使用できません。

https://code.google.com/p/android/issues/detail?id=38023

http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/5.0.0_r2-robolectric-1/android/view/LayoutInflater.java

于 2015-07-01T17:25:24.500 に答える
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" />

素敵なチュートリアルは次のとおりです

于 2012-06-29T16:13:44.650 に答える