SubwayTooter-Android-App/anko/src/main/java/org/jetbrains/anko/viewChildrenSequences.kt

161 lines
4.9 KiB
Kotlin

/*
* 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<View> = 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<View> = ViewChildrenRecursiveSequence(this)
private class ViewChildrenSequence(private val view: View) : Sequence<View> {
override fun iterator(): Iterator<View> {
if (view !is ViewGroup) return emptyList<View>().iterator()
return ViewIterator(view)
}
private class ViewIterator(private val view: ViewGroup) : Iterator<View> {
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<View> {
override fun iterator(): Iterator<View> {
if (view !is ViewGroup) return emptyList<View>().iterator()
return RecursiveViewIterator(view)
}
private class RecursiveViewIterator(view: View) : Iterator<View> {
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 <T : Any> MutableList<T>.removeLast(): T {
if (isEmpty()) throw NoSuchElementException()
return removeAt(size - 1)
}
}
}