【问题标题】:Android layout reference xml element later in file稍后在文件中的 Android 布局参考 xml 元素
【发布时间】:2015-08-04 20:27:47
【问题描述】:

如何引用后面的 XML 元素?

这是一个特定的用例。假设我有一个带有根 LinearLayout 的表单,其中包含多行的 LinearLayout,每一行都有一个或多个文本输入区域。

这是我要实现的目标的视觉效果。第一张图片来自 Venmo 的应用程序,第二张是以下 XML 的渲染。

这样的布局可能如下所示:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/row_card_number"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/card_number"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:nextFocusDown="@id/month"/>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/row_date"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/month"
            android:layout_height="wrap_content"
            android:layout_width="100dp"
            android:nextFocusDown="@id/year"/>

        <EditText
            android:id="@+id/year"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"/>
    </LinearLayout>
</LinearLayout>

在这个用例中,前向引用是必要的,以便设置下一个焦点元素。这样,当您按下键盘上的下一个按钮时,它将转到正确的视图。在这个示例 xml 中,如果没有 nextFocusDowns,按下一步会从名称转到月份,而永远不会转到年份。

但是,如果你尝试编译这个,你会得到一个错误:

错误:(18, 36) 未找到与给定名称匹配的资源(在 'nextFocusDown' 处,值为 '@id/month')。

这是因为 ID month 在我尝试引用它时尚未初始化,因为它在文件的后面。如何引用 xml 中稍后出现在文件中的 id?

【问题讨论】:

  • 这是一个自我回答的问题。我真的没有找到其他可以很好地解释这一点的东西,所以我想我会自己做。欢迎提出改进建议:)

标签: android xml android-layout android-linearlayout


【解决方案1】:

最简单的解决办法就是替换

android:nextFocusDown="@id/month"

android:nextFocusDown="@+id/month"

当编译器解析您的 XML 以将 id 添加到 R.java 时,它只是从上到下读取。当您有@id/month 时,它会搜索现有的 id,但找不到。

但是,如果您使用@+id/month,它会创建一个新的 ID,并链接到该 ID。当它在实际月份视图中到达 android:id=@+id/month 时,它会将其链接到我们已经创建的相同 id。


这就引出了一个问题:如果您可以将@id/ 替换为@+id/,并且@+id/ 将不管元素的顺序如何都可以工作,那么为什么还要费心使用@id/

原因是如果 id 不存在,@id/ 会抛出编译器错误,而@+id/ 会在运行时记录警告。

考虑这个 XML:

<EditText
    android:id="@+id/month"
    android:layout_height="wrap_content"
    android:layout_width="100dp"
    android:nextFocusDown="@+id/SOME_RANDOM_ID"/>

<EditText
    android:id="@+id/year"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>

解析后,会创建一个新的 id 元素 SOME_RANDOM_ID。但是,当 Android 尝试在运行时应用它时,它找不到具有该 id 的元素。如果您查看 Logcat,您会看到:

W/View:找不到 id 为 2131689604 的视图

此日志消息既难以找到也难以调试。 @+id/ 中的一个小错字,您将遇到一个非常难以调试的错误。但是,如果我们这样做了:

android:nextFocusDown="@id/SOME_RANDOM_ID"

然后我们会得到一个编译器错误,类似于:

错误:(18, 36) 未找到与给定名称匹配的资源(在“nextFocusDown”处,值为“@id/SOME_RANDOM_ID”)。

这更容易找到和调试。


tl;dr:您可以使用 @+id/ 而不是 @id/,并且您将能够转发引用,但请注意,这会使小错别字非常难以调试。

您也许可以使用 RelativeLayout 使所有视图在 xml 中以相反的顺序存在,但这对我来说似乎有点矫枉过正。

【讨论】:

    【解决方案2】:

    我最近遇到了同样的问题,我第一次引用元素时使用了 @+id/my_new_id,后来在元素定义的 XML 中,我分配了 @id/my_new_id android:id 属性。看起来它工作正常,没有必要多次使用相同的 id 写入 @+id 以避免可能的警告。

    例如:

    <LinearLayout
        ...
        android:layout_toLeftOf="@+id/my_new_id"
        ... >
    
    ...
    
    </LinearLayout>
    
    <ImageButton
        android:id="@id/my_new_id"
        ... />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-25
      相关资源
      最近更新 更多