Подтвердить что ты не робот

Включить макет с настраиваемыми атрибутами

Я делаю сложную компоновку, и я использую "include" для моего настраиваемого компонента, например

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

Но у меня нет результата. Я понял из этой страницы, что я не могу установить никаких атрибутов, но id, height и width.

Итак, как я могу передать свои настраиваемые атрибуты для включения и как заставить его работать?

4b9b3361

Ответ 1

Я знаю, что это старый вопрос, но я наткнулся на него и обнаружил, что теперь это возможно благодаря привязке данных.

Сначала вам нужно включить Связывание данных в вашем проекте.

Затем добавьте привязку данных к макету, который вы хотите включить:

<?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}"/>
...

Ответ 2

Невозможно использовать атрибуты, отличные от параметров макета, видимости или идентификатора в теге include. Сюда входят пользовательские атрибуты.

Вы можете проверить это, посмотрев на источник метода 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

Надуватель только применяет атрибуты идентификатора и видимости к включенному макету.

Ответ 3

Сегодня я столкнулся с этой проблемой. Что бы это ни стоило, я думаю, что есть прямая работа. Вместо добавления атрибутов в тег 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 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 для оболочки + 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>

На практике это работает очень хорошо и относительно просто настроить. Надеюсь, это поможет кому-то.

Ответ 4

К сожалению, единственное, что я могу внести, это то, что я также не смог установить пользовательские атрибуты в теге include и передать их во включенную компоновку.

На данном этапе это может быть невозможно.

Ответ 6

Вы должны включить в свой корневой элемент xml свое собственное пространство имен. Если ваше имя пакета com.example.test, ваш xml shold будет выглядеть примерно так:

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

Ответ 7

У меня был тот же вопрос. После посещения этого потока я закончил использование методов View setTag(), чтобы прикрепить идентификационную информацию к каждому View во время onCreate(), а затем getTag() методы для ее получения позже.