代码之家  ›  专栏  ›  技术社区  ›  Anubian Noob

文件后面的Android布局引用xml元素

  •  6
  • Anubian Noob  · 技术社区  · 11 年前

    如何引用稍后的XML元素?

    这里有一个具体的用例。假设我有一个具有根LinearLayout的表单,包含多行的LinearLayouts,每行都有一个或多个文本输入区域。

    这是我要去的地方。第一张图片来自Venmo的应用程序,第二张是以下XML的渲染图。

    Example of Venmo The layout

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

    <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中,没有 nextFocusDown s、 按下next键会从名字到月份,而不会转到年份。

    但是,如果您尝试编译它,您将得到一个错误:

    错误:(18,36)找不到与给定名称匹配的资源(位于“nextFocusDown”,值为“@id/month”)。

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

    2 回复  |  直到 11 年前
        1
  •  12
  •   Anubian Noob    11 年前

    最简单的解决方案就是更换

    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不存在, @身份证号码/ 将引发编译器错误,而 @+身份证号码/ 将在运行时记录警告。

    考虑此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的视图

    此日志消息很难找到,也很难调试。一个小错误 @+身份证号码/ 你会有一个调试起来非常困难的bug。然而,如果我们做到了:

    android:nextFocusDown="@id/SOME_RANDOM_ID"

    然后我们会得到一个编译器错误,比如:

    错误:(18,36)找不到与给定名称匹配的资源(位于“nextFocusDown”,值为“@id/SOME_RANDOM_id”)。

    这更容易查找和调试。


    tl;医生:你可以用 @+身份证号码/ 而不是 @身份证号码/ 您将能够转发引用,但请注意,这会使小的拼写错误难以调试。

    您可能可以使用RelativeLayout使所有视图在xml中以相反的顺序存在,但这对我来说似乎太过分了。

        2
  •  0
  •   Rafa Valle    9 年前

    我最近也有同样的问题 @+id/my_new_id 第一次引用元素,后来在元素定义中的XML中 @id/my_new_id 安卓:id 属性它似乎工作得很好,不必多次使用同一个id编写@+id,避免可能的警告。

    例如:

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