/* * Copyright 2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ @file:Suppress("unused") package org.jetbrains.anko import android.view.View import android.view.ViewGroup /** * Execute [action] for each child of the received [ViewGroup]. * * @param action the action to execute. */ @Deprecated( message = "Use the Android KTX version", replaceWith = ReplaceWith("forEach(action)", "androidx.core.view.forEach") ) inline fun ViewGroup.forEachChild(action: (View) -> Unit) { for (i in 0..childCount - 1) { action(getChildAt(i)) } } /** * Execute [action] for each child of the received [ViewGroup]. * * @param action the action to execute. The first index is 0. */ @Deprecated( message = "Use the Android KTX version", replaceWith = ReplaceWith("forEachIndexed(action)", "androidx.core.view.forEachIndexed") ) inline fun ViewGroup.forEachChildWithIndex(action: (Int, View) -> Unit) { for (i in 0..childCount - 1) { action(i, getChildAt(i)) } } /** * Return the first child [View] matching the given [predicate]. * * @param predicate the predicate to check against. * @return the child [View] that matches [predicate]. * [NoSuchElementException] will be thrown if no such child was found. */ inline fun ViewGroup.firstChild(predicate: (View) -> Boolean): View { return firstChildOrNull(predicate) ?: throw NoSuchElementException("No element matching predicate was found.") } /** * Return the first child [View] matching the given [predicate]. * * @param predicate the predicate to check against. * @return the child [View] that matches [predicate], or null if no such child was found. */ inline fun ViewGroup.firstChildOrNull(predicate: (View) -> Boolean): View? { for (i in 0..childCount - 1) { val child = getChildAt(i) if (predicate(child)) { return child } } return null } /** * Return the sequence of children of the received [View]. * Note that the sequence is not thread-safe. * * @return the [Sequence] of children. */ @Deprecated( message = "Use the Android KTX version", replaceWith = ReplaceWith("children", "androidx.core.view.children") ) fun View.childrenSequence(): Sequence = ViewChildrenSequence(this) /** * Return the [Sequence] of all children of the received [View], recursively. * Note that the sequence is not thread-safe. * * @return the [Sequence] of children. */ fun View.childrenRecursiveSequence(): Sequence = ViewChildrenRecursiveSequence(this) private class ViewChildrenSequence(private val view: View) : Sequence { override fun iterator(): Iterator { if (view !is ViewGroup) return emptyList().iterator() return ViewIterator(view) } private class ViewIterator(private val view: ViewGroup) : Iterator { private var index = 0 private val count = view.childCount override fun next(): View { if (!hasNext()) throw NoSuchElementException() return view.getChildAt(index++) } override fun hasNext(): Boolean { checkCount() return index < count } private fun checkCount() { if (count != view.childCount) throw ConcurrentModificationException() } } } private class ViewChildrenRecursiveSequence(private val view: View) : Sequence { override fun iterator(): Iterator { if (view !is ViewGroup) return emptyList().iterator() return RecursiveViewIterator(view) } private class RecursiveViewIterator(view: View) : Iterator { private val sequences = arrayListOf(view.childrenSequence()) private var current = sequences.removeLast().iterator() override fun next(): View { if (!hasNext()) throw NoSuchElementException() val view = current.next() if (view is ViewGroup && view.childCount > 0) { sequences.add(view.childrenSequence()) } return view } override fun hasNext(): Boolean { if (!current.hasNext() && sequences.isNotEmpty()) { current = sequences.removeLast().iterator() } return current.hasNext() } @Suppress("NOTHING_TO_INLINE") private inline fun MutableList.removeLast(): T { if (isEmpty()) throw NoSuchElementException() return removeAt(size - 1) } } }