【问题标题】:Using <include> tag with ?attr/myAttr将 <include> 标记与 ?attr/myAttr 一起使用
【发布时间】:2015-05-15 12:21:32
【问题描述】:

我正在尝试根据父 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:我将MainActivityTheme设置为android:theme="@style/AppTheme"

注意 #2: 在布局编辑器的设计视图中,一切都按预期工作。如果我切换主题,则包含会正确更新。
另请参阅以下屏幕截图:

【问题讨论】:

  • 从来没有想过这样做......希望有人回答,因为这是你发现的一个很酷的问题
  • 这种方式你不能包含基于主题的布局可能必须创建和加载主题基础布局。
  • @HareshChhelana 我不确定你想说什么。它认为奇怪的部分是布局编辑器可以解析属性,但运行时的代码也不能这样做。

标签: android android-layout android-styles android-attributes


【解决方案1】:

不幸的是,这是不可能的,但我真的很喜欢这个主意。我跟踪了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

基本上你没有做错任何事——预览中的通货膨胀的工作方式不同,这导致了混乱。

【讨论】:

  • 感谢您的出色回答。还有一件事我不明白:如果不是 TypedValue.TYPE_REFERENCEformat="reference" 是什么?
  • 这只是告诉你&lt;item name="themeLayout"&gt; 必须是TYPE_REFERENCE。如果您解析布局 XML 并找到 ?attr/themeLayout 它是 TYPE_ATTRIBUTE
  • 这是有道理的。谢谢你的解释。幸运的是 reVerse' approach 为我工作,它几乎类似于 &lt;include /&gt; 标签的东西
【解决方案2】:

由于Lamorak 在他的"in-depth" answer 中详细解释了所有内容,我想不用说&lt;include /&gt; 标签没有任何解决方案可以解决您的问题。
因此,请遵循在我的测试项目中有效的不同方法:

#1 - 替换 &lt;include /&gt; &lt;ViewStub /&gt;

<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 并且使用 &lt;merge /&gt; 标记将不起作用。

【讨论】:

    【解决方案3】:

    经过一番研究,我发现了这个问题-“在Android23中已经修复。但是波纹管,会抛出异常。

    【讨论】:

      猜你喜欢
      • 2012-11-16
      • 1970-01-01
      • 2015-12-02
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多