寻找一种在使用 kotlin 的活动中循环访问 ImageViews 的方法



我有一个活动,在 3x4 矩阵中有 12 个图像视图。我想以编程方式将每个 ImageView 的图像和其他属性替换为不同的资源。我似乎找不到任何方法通过循环遍历视图,因此我必须对每个更改进行硬编码。我设法将 ImageViews 放入一个有帮助的数组中,但我希望有更好的方法。我查看了 KotlinX.Synthetic 和数据/视图绑定,但它们似乎没有帮助。 例如,要创建 ImageView 数组,我必须这样做:

var imgArray = arrayOf(findViewById<ImageView>(R.id.img01))
imgArray += findViewById<ImageView>(R.id.img02)
imgArray += findViewById<ImageView>(R.id.img03)
imgArray += findViewById<ImageView>(R.id.img04)
imgArray += findViewById<ImageView>(R.id.img05)
imgArray += findViewById<ImageView>(R.id.img06)
imgArray += findViewById<ImageView>(R.id.img07)
imgArray += findViewById<ImageView>(R.id.img08)
imgArray += findViewById<ImageView>(R.id.img09)
imgArray += findViewById<ImageView>(R.id.img10)
imgArray += findViewById<ImageView>(R.id.img11)
imgArray += findViewById<ImageView>(R.id.img12)

我希望做这样的事情:

var i = 1
for (listView in listViews) {
imgArray += findViewById<ImageView>("R.id.img" + i.tostring())
i++
}

但这行不通。 任何帮助将不胜感激。我有一些其他语言的经验,但对 kotlin/java/android 很陌生。

我通常走的路是

val imageViews = listOf(R.id.img1, R.id.img2, R.id.img3).map(findViewById(it)) 

这将在一行中构建视图列表。

或者,如果您真的不想使列表保持最新并且名称没有变化,那么获取给定名称的 idresources.getIdentifier("nameOfDrawable", "drawable", this.getPackageName())

我通常使用Gabe答案中的第一个示例,只是列出ID并使用它来创建可以迭代的有用集合。但根据情况,这里有几个其他选项可能更合适:

查找给定类型的所有视图

container.children.filterIsInstance<ImageView>()

这需要对ViewGroup(例如ConstraintLayoutGridLayout等)的引用,基本上提取出某种类型的所有View。如果它们以某种容器布局进行组织,则很有用,如果所有内容都在同一级别(例如鼓励您这样做的ConstraintLayout),并且您不想包含其他相同类型的View,则不会很有用。

此外,这仅适用于容器的直接后代,即将其作为父级的东西。如果这些东西中的任何一个有自己的后代,它们不包括在内(不过请参阅下面的函数!

使用标签

标记是可以添加到View的一些数据,在具有tag属性的 XML 中,或在具有setTag的代码中。您可以使用它来确定您想要的ImageView,如果无法在层次结构中组织它们。(层次结构更好,因为一旦设置,就没有工作,也没有什么可忘记的 - 您只需将视图与其他视图放在一起即可。

有一个findViewWithTag函数,但它只返回一个View,当你有一个想要抓取的组时,这是不好的。因此,我们可以编写一个辅助函数来获取ViewGroup的所有后代(而不仅仅是其直系子代):

fun ViewGroup.getAllDescendants(): Sequence<View> =
children + children.filterIsInstance<ViewGroup>().flatMap { it.getAllDescendants() }

(这很有用,因为它可以处理嵌套层次结构中的View,因此如果您有一个容器,您需要的所有内容都在内部,但作为内部层次结构的一部分,它也可以帮助上述filterByInstance方法。

现在,您可以使用它来获取层次结构中的每个View,并筛选所需的标签

// start with the root view, e.g. 'view' or 'binding.root' - or any container
// you want to search inside
(view as ViewGroup).getAllDescendants()
// you don't necessarily need to do this one, but it's safer and casts for you
.filterIsInstance<ImageView>()
.filter { it.tag == "cool image" }

如果 ImageView 位于同一父布局上,则只需查询布局的子布局。

你会得到一个儿童名单。

迭代列表。

您不必在正手上知道有多少图像视图。

最新更新