如何以编程方式为视图分配ID?


202

在XML文件中,我们可以为视图分配ID android:id="@+id/something",然后调用findViewById(),但是以编程方式创建视图时,如何分配ID?

我认为setId()与默认分配不同。setId()是额外的。

有人可以纠正我吗?


Answers:


521

Android id概述

Android id是通常用于标识视图的整数;这id可以通过XML(如果可能),并且经由代码分配(编程)的id是获得用于XML定义的引用最有用的View由生成S- Inflater(诸如通过使用setContentView)。

id通过分配XML

  • 的属性添加android:id="@+id/somename "到您的视图。
  • 构建应用程序后,android:id将为代码分配一个唯一 int的代码。
  • 使用“ somename”(实际上是一个常量)在代码中引用您android:idintR.id.
  • int可能会因版本而异,因此切勿gen/package.name/ 复制IDR.java,只需使用“ R.id.somename”即可。
  • (此外,在XML 生成时,不使用XML中的id分配给。)PreferencePreferenceView

id通过代码分配(以编程方式)

  • id使用someView.setId(int 手动设置);
  • int必须是积极的,但另有arbitrary-它可以是任何你想要的(请继续阅读,如果这是可怕的。)
  • 例如,如果创建和编号代表项目的多个视图,则可以使用其项目编号。

唯一性id小号

  • XML-assigned id是唯一的。
  • 代码分配id就做必须是唯一的
  • 代码分配的ids(理论上)可以与XML-assigned id的冲突。
  • id如果正确查询(保持阅读),则这些冲突s无关紧要。

何时(以及为什么)冲突id无关紧要

  • findViewById(int)将从指定的View递归遍历视图层次结构的深度优先,并返回View它找到的第一个具有match的对象id
  • 只要在层次结构中id的XML定义之前没有分配代码分配idfindViewById(R.id.somename)就将始终返回XML定义的视图id

动态创建视图并分配IDs

  • 在布局XML,定义一个空ViewGroupid
  • LinearLayoutandroid:id="@+id/placeholder"
  • 使用代码来填充占位ViewGroupView秒。
  • 如果需要,请id为每个视图分配任何方便的。
  • 使用placeholder.findViewById(convenientInt);查询这些子视图;

  • 引入了API 17 View.generateViewId(),使您可以生成唯一的ID。

如果选择保留对视图的引用,请确保使用实例化它们,getApplicationContext()并确保在中将每个引用设置为null onDestroy。显然,泄漏Activity(挂到它之后被销毁)是一种浪费.. :)

保留XML android:id以在代码中使用

引入了API 17 View.generateViewId() ,该API 生成唯一的ID。(感谢您指出这一点。)*

如果您ViewGroup不能通过XML定义您的ID(或者您不希望这样),则可以通过XML保留ID以确保其唯一性:

在这里,values / ids.xml定义了一个自定义id

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="reservedNamedId" type="id"/>
</resources>

然后,一旦创建了ViewGroup或View,就可以附加自定义ID

myViewGroup.setId(R.id.reservedNamedId);

矛盾的id例子

为了清楚起见,通过混淆示例,让我们检查id在幕后发生冲突时会发生什么。

layout / mylayout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/placeholder"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
</LinearLayout>

为了模拟冲突,可以说我们的最新版本为R.id.placeholder@+id/placeholder)分配了。int 12

接下来,MyActivity.java以编程方式(通过代码)定义一些添加视图:

int placeholderId = R.id.placeholder; // placeholderId==12
// returns *placeholder* which has id==12:
ViewGroup placeholder = (ViewGroup)this.findViewById(placeholderId);
for (int i=0; i<20; i++){
    TextView tv = new TextView(this.getApplicationContext());
    // One new TextView will also be assigned an id==12:
    tv.setId(i);
    placeholder.addView(tv);
}

因此placeholder,我们的一个新产品TextView都有一个id12!但是,如果我们查询占位符的子视图,这实际上不是问题:

// Will return a generated TextView:
 placeholder.findViewById(12);

// Whereas this will return the ViewGroup *placeholder*;
// as long as its R.id remains 12: 
Activity.this.findViewById(12);

*还不错


9
除此之外,对于编码类似解决方案的人来说,了解API> 17中的非冲突ID可能对有用的人有所了解
AllDayAmazing 2014年

请注意,这findViewById是进行深度优先的探索,因此“只要在层次结构中XML定义的ID上方没有分配代码分配的ID”在技术上就不正确;它是“之前”而不是“之上”。
卡鲁2014年

在更新版本的Android开发人员工具中,以编程方式将ID设置为任意值将被标记为编译器错误。该值应该是实际的资源ID。
ThomasW

我相信甚至在我五年前回答这个问题时也是如此-这就是为什么必须在中定义自定义ID的原因ids.xml。对于真正任意的ID,请使用View.generateViewId()(API 17)。(如果我错过了,请澄清您的观点。)
CodeShane,2017年

>(此外,当Preference生成其View时,不使用分配给XML中的Preference的ID。)对此非常感兴趣。我的代码继承自PreferenceDialogFragmentCompat它,好像ids from R.id与视图层次结构不匹配。这样,我无法通过ID查找视图。
UrK

6

您可以View.setId(integer)为此使用。在XML中,即使您设置了String id,它也将转换为整数。因此,您可以以Views 编程方式添加任何(正)整数。

根据View文件

标识符在此视图的层次结构中不必唯一。标识符应为正数。

因此,您可以使用任何喜欢的正整数,但是在这种情况下,可能会有一些具有相同ID的视图。如果要在层次结构中搜索某些视图,则可以使用一些关键对象调用setTag。

归功于这个答案


5

是的,您可以setId(value)在任何视图中使用所需的任何(正)整数值进行调用,然后使用在父容器中找到它findViewById(value)。请注意,setId()对于不同的同级视图使用相同的值进行调用是有效的,但findViewById()只会返回第一个。


1
请注意,您必须使用大于零的整数。
彼得·阿杰泰

尽管findViewById(int)将从您指定的View递归遍历视图层次结构,然后返回它找到的第一个具有第一个答案中指定的ID的匹配ID的第一个View是最准确的。
Aniket Thakur

是的,findViewById出于性能方面的考虑,拜访一位已知的祖先是个好主意,但不能保证如果有一个具有正确ID的孩子,它将找到一个直系孩子。
卡鲁2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.