我如何以编程方式将ID分配给视图?

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

我认为setId()是不一样的默认分配。 setId()是额外的。

有人可以纠正我吗?

Android id概览

Android id是一个通常用于识别视图的整数。 这个id可以通过XML(如果可能的话)和通过代码(以编程方式)分配。id对于获取由Inflater生成的XML定义的View的引用(例如通过使用setContentView )是非常有用的。

通过XML分配id

  • android:id="@+id/ somename "的属性添加到您的视图中。
  • 在构build应用程序时, android:id将被分配一个唯一的 int用于代码。
  • 在代码中使用“ R.id. somename”引用你的android:idint值(实际上是一个常量)。
  • 这个int可以从构build变为构build,所以不要gen/ package.name gen/ R.java 复制一个id ,只需使用“ R.id. somename”即可。
  • (此外,在Preference生成View时,不会使用分配给XML中的Preferenceid

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

  • 手动设置id使用someView.setId( INT );
  • int必须是正数,但在其他方面是任意的 – 它可以是任何你想要的(如果这是可怕的,请继续阅读)。
  • 例如,如果创build和编号代表项目的几个视图,您可以使用他们的项目编号。

id的唯一性

  • XML分配的id将是唯一的。
  • 代码分配的id不必是唯一的
  • 代码分配的id可以(理论上)与XML分配的id冲突。
  • 如果查询正确,这些冲突的id将无关紧要(继续阅读)

何时(以及为什么)冲突的id不重要

  • findViewById(int)将从您指定的View中recursion地遍历视图层次结构并返回它find的第一个View和一个匹配的id
  • 只要在层次结构中的XML定义的id之前没有分配代码分配的idfindViewById(R.id.somename)将始终返回XML定义的View,因此id “d”。

dynamic创build视图并分配ID

  • 在布局XML中,用id定义一个空的ViewGroup
  • 比如带有android:id="@+id/placeholder"LinearLayout
  • 使用代码使用View来填充占位符ViewGroup
  • 如果您需要或想要,请为每个视图指定方便的id
  • 使用placeholder.findViewById(convenienceInt)查询这些子视图;

  • API 17引入了View.generateViewId() ,它允许你生成一个唯一的ID。

如果select保持对视图的引用,请确保使用getApplicationContext()实例化它们,并确保在onDestroy中将每个引用设置为null。 显然泄露 Activity (挂在它后被销毁)是浪费.. 🙂

保留用于代码的XML android:id

API 17引入了 View.generateViewId() ,它生成一个唯一的ID。 (感谢冒险做出改变,指出这一点。)*

如果你的ViewGroup不能通过XML来定义(或者你不想这样做),你可以通过XML保留这个id来确保它是唯一的:

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

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

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

 myViewGroup.setId(R.id.reservedNamedId); 

相冲突的例子

通过混淆示例的方式来澄清,让我们来看看在幕后出现id冲突时会发生什么。

布局/ 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都有一个12的id ! 但是,如果我们查询占位符的子视图,这不是一个真正的问题:

 // 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); 

*不那么糟糕

你可以使用View.setId(integer) 。 在XML中,即使您设置了stringID,也会将其转换为整数。 由于这个原因,您可以使用任何(正数)整数来以编程方式添加的Views

根据View文档

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

所以你可以使用你喜欢的任何正整数,但在这种情况下,可以有一些视图与等效的ID。 如果你想在层次结构中search一些视图,调用setTag和一些关键对象可能会很方便。

学分到这个答案 。

是的,您可以在任何视图中使用您喜欢的任何(正数)整数值调用setId(value) ,然后使用findViewById(value)在父容器中find它。 请注意,为不同的同级视图调用setId()具有相同的值是有效的,但findViewById()将仅返回第一个。