Используя tag with?attr / myAttr

Я пытаюсь включить различные макеты в моем представлении в зависимости от родителя Theme.

следующая идея:

attrs.в XML

<attr name="themeLayout" format="reference" />

стили.в XML

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="themeLayout">@layout/layout_a</item>
</style>

<style name="AppThemeSecond" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="themeLayout">@layout/layout_b</item>
</style>

активности.в XML

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <include layout="?attr/themeLayout" />

</RelativeLayout>

когда я запускаю код выше, я получаю следующее исключение:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.package/com.my.package.MainActivity}: android.view.InflateException: You must specifiy a valid layout reference. The layout ID ?attr/themeLayout is not valid.
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
            at android.app.ActivityThread.access0(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: android.view.InflateException: You must specifiy a valid layout reference. The layout ID ?attr/themeLayout is not valid.
            at android.view.LayoutInflater.parseInclude(LayoutInflater.java:866)

что я делаю не так? Возможно ли это вообще?

Примечание #1: я поставил Theme моего MainActivity to android:theme="@style/AppTheme"

примечание #2: в Design-View редактора макета все работает так, как ожидалось. Если я переключу тему, include будет обновлен должным образом.
Смотрите также следующие скриншоты:

preview design tab android studio

3 ответов


к сожалению, это невозможно, но мне очень нравится идея. Я отследил поток LayoutInflater и это требует на TypedValue.TYPE_REFERENCE что означает ?attr не допускается. Они даже оставили комментарий в методе объяснения.

public int getAttributeResourceValue(int idx, int defaultValue) {
    int t = nativeGetAttributeDataType(mParseState, idx);
    // Note: don't attempt to convert any other types, because
    // we want to count on aapt doing the conversion for us.
    if (t == TypedValue.TYPE_REFERENCE) {
        return nativeGetAttributeData(mParseState, idx);
    }
    return defaultValue;
}

android.содержание.РЭС.XmlBlock.java: 385

в основном вы не сделали ничего плохого - инфляция в предварительном просмотре работает по-разному, что вызвало путаницу.


С Lamorak объяснил все подробно в своем "углубленный" ответ Я думаю, можно сказать, что нет никакого решения с <include /> тег для вашей проблемы.
Итак, следуя другому подходу, который работал в моем тестовом проекте:

#1 - заменить <include /> С <ViewStub />

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ViewStub
        android:id="@+id/myStub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inflatedId="@+id/myInflatedStub"
        android:layout="?attr/themeLayout" />

</RelativeLayout>

#2 - надуть ViewStub

ViewStub myStub = (ViewStub) findViewById(R.id.myStub);
myStub.inflate();

любые недостатки с этим метод? Ну, вы не увидите ViewStub-Layout в своей вкладке Design и с помощью <merge /> тег не будет работать.


после некоторых исследований, я нашел эту проблему-"исправлено в Android23. Но мехи, исключение будет брошено.