Ищем в глубину: сначала проверяем root, затем детей ViewGroup. Для безопасного возврата конкретного типа можно использовать inline-функцию с reified-параметром.
Создание собственного аналога findViewById для View
Ищем в глубину: сначала проверяем root, затем детей ViewGroup. Для безопасного возврата конкретного типа можно использовать inline-функцию с reified-параметром.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо реализовать функцию, которая будет искать вложенный View по его идентификатору, имитируя поведение стандартного метода findViewById. При написании решения можно воспользоваться следующими свойствами и функциями, предоставленными в SDK:
View.id: IntViewGroup.childCount: Intfun ViewGroup.getChildAt(index: Int): Viewfun ViewGroup.children(): Sequence<View>
Требуется написать универсальную функцию, возвращающую найденный элемент нужного типа или null, если элемент с указанным id не найден.
fun <T: View> findViewById(root: View, id: Int): T?
Ответ
Ищем в глубину: сначала проверяем root, затем детей ViewGroup. Для безопасного возврата конкретного типа можно использовать inline-функцию с reified-параметром.
Вариант с проверкой типа во время выполнения:
inline fun <reified T : View> findViewById(root: View, id: Int): T? {
if (id == View.NO_ID) return null
val stack = java.util.ArrayDeque<View>()
stack.addLast(root)
while (stack.isNotEmpty()) {
val node = stack.removeLast()
if (node.id == id) return node as? T
if (node is ViewGroup) {
for (i in node.childCount - 1 downTo 0) {
stack.addLast(node.getChildAt(i))
}
}
}
return null
}
В худшем случае O(n) по числу View. Добавление reified уточняет предложенную сигнатуру: без него T стирается и безопасно проверить фактический тип нельзя без отдельного Class<T>. Стек заменяет рекурсию и сохраняет порядок обхода детей.