Использование тега <include> с? Attr/myAttr
Я пытаюсь включить разные макеты в моем представлении в зависимости от родителя Theme
,
Следуя идее:
attrs.xml
<attr name="themeLayout" format="reference" />
styles.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>
activity.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.access$800(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
в android:theme="@style/AppTheme"
Примечание № 2: В Design-View редактора макетов все работает как положено. Если я переключаю тему, включается правильно обновляется.
Смотрите также следующие скриншоты:
3 ответа
К сожалению, это невозможно, но мне очень нравится эта идея. Я отслеживал поток LayoutInflater
и это требует layout
атрибут быть 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.content.res.XmlBlock.java:385
По сути, вы не сделали ничего плохого - инфляция в Preview работает по-другому, что привело к путанице.
Поскольку 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. Но ниже, исключение будет выброшено.