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

Posted

技术标签:

【中文标题】如何以编程方式将 ID 分配给视图?【英文标题】:How can I assign an ID to a view programmatically? 【发布时间】:2011-12-10 23:17:12 【问题描述】:

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

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

有人可以纠正我吗?

【问题讨论】:

子集:如何生成唯一 ID:***.com/questions/1714297/… 【参考方案1】:

Android id 概览

Android id 是一个整数,常用于标识视图; id 可以通过 XML(如果可能)和代码(以编程方式)分配。id 对于获取由Inflater 生成的 XML 定义的 Views 的引用最有用(例如通过使用 @ 987654327@.)

通过XML分配id

android:id="@+id/somename" 属性添加到您的视图中。 构建您的应用程序后,android:id 将被分配一个唯一 int 以供在代码中使用。 使用“R.id.somename”(实际上是一个常量)在代码中引用您的 android:idint 值。 这个int 可以在不同版本之间变化,所以永远不要从gen/package.name/R.java 复制一个ID,只需使用“R.id.somename”。 (此外,当Preference 生成其View 时,不使用分配给XML 中Preferenceid。)

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

使用someView.setId(int);手动设置ids int 必须是肯定的,否则是任意的 - 它可以是任何你想要的(如果这很可怕,请继续阅读。) 例如,如果创建多个表示项目的视图并为其编号,则可以使用它们的项目编号。

ids 的唯一性

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

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

findViewById(int) 将在视图层次结构中递归迭代深度优先从您指定的视图,并返回它找到的第一个 View 与匹配的 id。 只要在层次结构中 XML 定义的 id 之前没有分配代码分配的 ids,findViewById(R.id.somename) 将始终返回 XML 定义的视图,因此 id'd。

动态创建视图并分配IDs

在布局 XML 中,使用 id 定义一个空的 ViewGroup比如LinearLayoutandroid:id="@+id/placeholder" 使用代码以Views 填充占位符ViewGroup。 如果您需要或想要,为每个视图分配任何方便的ids。

使用 placeholder.findViewById(convenientInt);查询这些子视图;

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

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

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

API 17 引入View.generateViewId() 生成唯一 ID。(感谢 take-chances-make-changes 指出这一点。)*

如果您的ViewGroup 无法通过 XML 定义(或者您不希望这样),您可以通过 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_
    android:layout_
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/placeholder"
        android:layout_
        android:layout_
        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 和我们的一个新TextViews 都有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);

*还不错

【讨论】:

除此之外,对于编写类似解决方案的人来说,了解 API > 17 中的 View.generateViewId() 对于非冲突 ID 可能会有用 请注意,findViewById 进行深度优先探索,因此“只要在层次结构中 XML 定义的 id 之上没有分配代码分配的 id”在技术上是不正确的;它是“之前”而不是“之上”。 在较新版本的 Android 开发者工具中,以编程方式将 ID 设置为任意值将被标记为编译器错误。该值应为实际的资源 ID。 我相信五年前我回答这个问题时就是这种情况 - 这就是为什么必须在 ids.xml 中定义自定义 ID。对于真正的任意 ID,请使用 View.generateViewId() (API 17)。 (如果我错过了,请澄清你的观点。) > (此外,当 Preference 生成其视图时,不使用分配给 XML 中的 Preference 的 id。)对此非常感兴趣。我的代码继承自 PreferenceDialogFragmentCompat 似乎来自 R.id 的 id 与那些视图层次结构不匹配。这样我就无法通过 ID 找到视图。【参考方案2】:

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

根据View文档

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

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

感谢this answer。

【讨论】:

【参考方案3】:

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

【讨论】:

请注意,您必须使用大于零的整数。 虽然 findViewById(int) 将从您指定的视图中递归遍历视图层次结构并返回它找到的第一个具有匹配 id 的视图 在第一个答案中指定是最准确的. 是的,出于性能原因,在已知祖先上调用 findViewById 是一个好主意,但它不能保证如果存在具有正确 ID 的直接子代,它会找到直系子代。

以上是关于如何以编程方式将 ID 分配给视图?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式将按钮添加到 gridview 并将其分配给特定的代码隐藏函数?

以编程方式将位置分配给android中的按钮

快速将约束分配给视图的最简单方法?

以编程方式填充分配给对象的属性集定义中的数据

以编程方式创建的 rootviewcontroller 未显示分配的 viewcontroller 的内容

使用 C++ 以编程方式将新字母分配给现有驱动器