将 <include> 标签与 ?attr/myAttr 一起使用
Using <include> tag with ?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.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: 我将 MainActivity
的 Theme
设置为 android:theme="@style/AppTheme"
注意 #2: 在布局编辑器的设计视图中,一切都按预期进行。如果我切换主题,包含会正确更新。
另请参阅以下屏幕截图:
不幸的是,这是不可能的,但我真的很喜欢这个主意。我已经跟踪了 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
基本上您没有做错任何事 -- 预览中的 inflation 工作方式不同,这导致了混淆。
因为 Lamorak explained everything in detail in his 我想可以肯定地说 <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,使用 <merge />
标签也不起作用。
经过一些研究,我发现了这个问题-已经在Android23中修复了。但是波纹管,会抛出异常。
我正在尝试根据父 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.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: 我将 MainActivity
的 Theme
设置为 android:theme="@style/AppTheme"
注意 #2: 在布局编辑器的设计视图中,一切都按预期进行。如果我切换主题,包含会正确更新。
另请参阅以下屏幕截图:
不幸的是,这是不可能的,但我真的很喜欢这个主意。我已经跟踪了 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
基本上您没有做错任何事 -- 预览中的 inflation 工作方式不同,这导致了混淆。
因为 Lamorak explained everything in detail in his <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,使用 <merge />
标签也不起作用。
经过一些研究,我发现了这个问题-已经在Android23中修复了。但是波纹管,会抛出异常。