• 使用Kotlin对ViewGroup的视图进行函数使操作


    原文标题:Functional operations over Views in ViewGroup using Kotlin

    原文链接:http://antonioleiva.com/functional-operations-viewgroup-kotlin/

    原文作者:Antonio Leiva(http://antonioleiva.com/about/

    原文发布:2015-07-29

    集合、迭代、数组、序列 ... 所有这些共用一套好用的函数,这组函数可帮助对它们的元素进行转换、排序以及其它操作。但是,由于类的构造方法,在Android SDK中,有部分函数还不能用。

    例如,我们不能直接获得ViewGroup内部视图列表,所以这些操作是不可能使用的。但是并非所有一切都失去了。在Kotlin中,我们有方法为这些操作准备任何数据。诀窍简单:我们只需要创建一个Sequence。在我们的例子中,Sequence将是一组有序的View。我们只需要实现一个函数,其返回Iterator

    如果我们有了Sequence,函数式操作领域就为我们打开了使用它们的大门。所以让我们从它开始。

    注:阅读文章结尾

    如lakedaemon666在评论中所建议的那样,有一个不用Sequence的更简单的方法可以获得同样的结果。我会保留原文记录,但是建议你看看替代的解决方案。

    创建ViewGroup的Sequence

    如前所述,我们将创建迭代器(iterator),它必须知道是否有下一项,下一项是哪个。我们还创建一个扩展函数,为了任何 ViewGroup 和继承类提供一个简单的方法做那项工作:

     1 fun ViewGroup.asSequence(): Sequence<View> = object : Sequence<View> {
     2  
     3     override fun iterator(): Iterator<View> = object : Iterator<View> {
     4         private var nextValue: View? = null
     5         private var done = false
     6         private var position: Int = 0
     7  
     8         override public fun hasNext(): Boolean {
     9             if (nextValue == null && !done) {
    10                 nextValue = getChildAt(position)
    11                 position++
    12                 if (nextValue == null) done = true
    13             }
    14             return nextValue != null
    15         }
    16  
    17         override fun next(): View {
    18             if (!hasNext()) {
    19                 throw NoSuchElementException()
    20             }
    21             val answer = nextValue
    22             nextValue = null
    23             return answer!!
    24         }
    25     }
    26 }

    检索视图递归列表

    获得一个视图列表,并对其进行函数操作是非常有用的。因此,我们可以先创建顶层视图列表,然后,用它以递归方式逐级检索ViewGroup中视图。

    让我们为ViewGroup创建新扩展属性。扩展属性非常类似扩展函数,可用于任何类:

    1 public val ViewGroup.views: List<View>
    2     get() = asSequence().toList()

    我们可以用这,创建递归函数,它返回布局中任何ViewGroup内部的所有View

    1 public val ViewGroup.viewsRecursive: List<View>
    2     get() = views flatMap {
    3         when (it) {
    4             is ViewGroup -> it.viewsRecursive
    5             else -> listOf(it)
    6         }
    7     }

    flatMap,我们把全部结果的多个列表转换到一个列表中。它将遍历任何视图;如果是ViewGroup,它还会遍历自己的视图。否则,就返回仅有一项的列表。

    用法实例

    现在,我们得到viewRecursive属性,执行我们想要的任何操作。这里你可以看到两个例子。我创建这样一个简单的布局:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2                 xmlns:tools="http://schemas.android.com/tools"
     3                 android:id="@+id/container"
     4                 android:layout_width="match_parent"
     5                 android:layout_height="match_parent"
     6                 android:paddingBottom="@dimen/activity_vertical_margin"
     7                 android:paddingLeft="@dimen/activity_horizontal_margin"
     8                 android:paddingRight="@dimen/activity_horizontal_margin"
     9                 android:paddingTop="@dimen/activity_vertical_margin"
    10                 tools:context=".MainActivity">
    11  
    12     <TextView
    13         android:layout_width="wrap_content"
    14         android:layout_height="wrap_content"
    15         android:text="@string/hello_world"/>
    16  
    17     <FrameLayout
    18         android:layout_width="match_parent"
    19         android:layout_height="wrap_content"
    20         android:layout_centerInParent="true">
    21  
    22         <TextView
    23             android:layout_width="wrap_content"
    24             android:layout_height="wrap_content"
    25             android:text="Hello Java"/>
    26  
    27         <TextView
    28             android:layout_width="wrap_content"
    29             android:layout_height="wrap_content"
    30             android:layout_gravity="center_horizontal"
    31             android:text="Hello Kotlin"/>
    32  
    33         <TextView
    34             android:layout_width="wrap_content"
    35             android:layout_height="wrap_content"
    36             android:layout_gravity="end"
    37             android:text="Hello Scala"/>
    38  
    39     </FrameLayout>
    40  
    41     <LinearLayout
    42         android:layout_width="match_parent"
    43         android:layout_height="wrap_content"
    44         android:layout_alignParentBottom="true"
    45         android:orientation="horizontal">
    46  
    47         <CheckBox
    48             android:layout_width="wrap_content"
    49             android:layout_height="wrap_content"
    50             android:text="Check 1"/>
    51  
    52         <CheckBox
    53             android:layout_width="wrap_content"
    54             android:layout_height="wrap_content"
    55             android:text="Check 2"/>
    56  
    57         <CheckBox
    58             android:layout_width="wrap_content"
    59             android:layout_height="wrap_content"
    60             android:text="Check 3"/>
    61  
    62         <CheckBox
    63             android:layout_width="wrap_content"
    64             android:layout_height="wrap_content"
    65             android:text="Check 4"/>
    66  
    67     </LinearLayout>
    68  
    69 </RelativeLayout>

     例如,在MainActivity.onCreate()中,可应用这段代码。它将Hello Kotlin!串转换为大写字母,选中偶数复选框:

     1 val container: ViewGroup = find(R.id.container)
     2 val views = container.viewsRecursive
     3  
     4 // Set Kotlin TextView to Upper
     5 val kotlinText = views.first {
     6     it is TextView && it.text.toString().contains("Kotlin")
     7 } as TextView
     8 kotlinText.text = kotlinText.text.toString().toUpperCase()
     9  
    10 // Set even checkboxes as checked, and odd as unchecked
    11 views filter {
    12     it is CheckBox
    13 } forEach {
    14     with(it as CheckBox) {
    15         val number = text.toString().removePrefix("Check ").toInt()
    16         setChecked(number % 2 == 0)
    17     }
    18 }

    替代的解决方案

    如lakedaemon666在评论中所提及的那样(谢谢解释),如果之后我们遍历整个sequence,那么创建sequence就没有什么意义了。例如,当按行读取文件时,sequence是懒惰迭代。只有要求必要的项目。而我们却要使用所有项,所以简单的列表就足够了。

    另外,有许多简单的方法可以产生视图列表。我们可以依赖值域产生视图的索引列表,将它们映射到我们需要的视图列表中。所有这一切就一行:

    1 public val ViewGroup.views: List<View>
    2     get() = (0..getChildCount() - 1) map { getChildAt(it) }

    总结

    这是个无聊的例子,但是这个概念或许可使你的所有代码函数化,停止依靠那些典型迭代式编程的循环和其它控制流。

    记住从我写的书《Android开发者的Kotlin》中,你能够学习到Kotlin的这点以及许多其它能力,你将通过从0开始创建Android APP学习Kotlin。

  • 相关阅读:
    SKPhysicsJointPin类
    SKPhysicsJointLimit类
    SKPhysicsJointFixed类
    SKPhysicsJoint类
    SKPhysicsContact类
    SKPhysicsBody类
    SKLabelNode类
    SKNode类
    SKKeyframeSequence类
    Unique Paths II
  • 原文地址:https://www.cnblogs.com/figozhg/p/5017316.html
Copyright © 2020-2023  润新知