使用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 和继承类提供一个简单的方法做那项工作:
fun ViewGroup.asSequence(): Sequence<View> = object : Sequence<View> { override fun iterator(): Iterator<View> = object : Iterator<View> {
private var nextValue: View? = null
private var done = false
private var position: Int = 0 override public fun hasNext(): Boolean {
if (nextValue == null && !done) {
nextValue = getChildAt(position)
position++
if (nextValue == null) done = true
}
return nextValue != null
} override fun next(): View {
if (!hasNext()) {
throw NoSuchElementException()
}
val answer = nextValue
nextValue = null
return answer!!
}
}
}
检索视图递归列表
获得一个视图列表,并对其进行函数操作是非常有用的。因此,我们可以先创建顶层视图列表,然后,用它以递归方式逐级检索ViewGroup
中视图。
让我们为ViewGroup
创建新扩展属性。扩展属性非常类似扩展函数,可用于任何类:
public val ViewGroup.views: List<View>
get() = asSequence().toList()
我们可以用这,创建递归函数,它返回布局中任何ViewGroup
内部的所有View
:
public val ViewGroup.viewsRecursive: List<View>
get() = views flatMap {
when (it) {
is ViewGroup -> it.viewsRecursive
else -> listOf(it)
}
}
用flatMap
,我们把全部结果的多个列表转换到一个列表中。它将遍历任何视图;如果是ViewGroup,它还会遍历自己的视图。否则,就返回仅有一项的列表。
用法实例
现在,我们得到viewRecursive
属性,执行我们想要的任何操作。这里你可以看到两个例子。我创建这样一个简单的布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"/> <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Java"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Hello Kotlin"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="Hello Scala"/> </FrameLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"> <CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check 1"/> <CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check 2"/> <CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check 3"/> <CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check 4"/> </LinearLayout> </RelativeLayout>
例如,在MainActivity.onCreate()
中,
可应用这段代码。它将Hello Kotlin!
串转换为大写字母,选中偶数复选框:
val container: ViewGroup = find(R.id.container)
val views = container.viewsRecursive // Set Kotlin TextView to Upper
val kotlinText = views.first {
it is TextView && it.text.toString().contains("Kotlin")
} as TextView
kotlinText.text = kotlinText.text.toString().toUpperCase() // Set even checkboxes as checked, and odd as unchecked
views filter {
it is CheckBox
} forEach {
with(it as CheckBox) {
val number = text.toString().removePrefix("Check ").toInt()
setChecked(number % 2 == 0)
}
}
替代的解决方案
如lakedaemon666在评论中所提及的那样(谢谢解释),如果之后我们遍历整个sequence,那么创建sequence就没有什么意义了。例如,当按行读取文件时,sequence是懒惰迭代。只有要求必要的项目。而我们却要使用所有项,所以简单的列表就足够了。
另外,有许多简单的方法可以产生视图列表。我们可以依赖值域产生视图的索引列表,将它们映射到我们需要的视图列表中。所有这一切就一行:
public val ViewGroup.views: List<View>
get() = (0..getChildCount() - 1) map { getChildAt(it) }
总结
这是个无聊的例子,但是这个概念或许可使你的所有代码函数化,停止依靠那些典型迭代式编程的循环和其它控制流。
记住从我写的书《Android开发者的Kotlin》中,你能够学习到Kotlin的这点以及许多其它能力,你将通过从0开始创建Android APP学习Kotlin。
使用Kotlin对ViewGroup的视图进行函数使操作的更多相关文章
- 用Kotlin实现Android定制视图(KAD 06)
作者:Antonio Leiva 时间:Dec 27, 2016 原文链接:https://antonioleiva.com/custom-views-android-kotlin/ 在我们阅读有关c ...
- onAttachedToWindow () 和 onDetachedFromWindow () ; 以及更新视图的函数ondraw() 和dispatchdraw()的区别
protected void onAttachedToWindow() This is called when the view is attached to a window. At this po ...
- MS SQL Server中数据表、视图、函数/方法、存储过程是否存在判断及创建
前言 在操作数据库的时候经常会用到判断数据表.视图.函数/方法.存储过程是否存在,若存在,则需要删除后再重新创建.以下是MS SQL Server中的示例代码. 数据表(Table) 创建数据表的时候 ...
- .Net程序员学用Oracle系列(7):视图、函数、过程、包
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.视图 1.1.创建视图 2.函数 2.1.创建函数 2.2.调用函数 3.过程 3.1.创建过程 3.2.调用过程 4.包 ...
- .Net程序员学用Oracle系列(7):视图、函数、存储过程、包
1.视图 1.1.创建.删除及调用普通视图 1.2.高级视图介绍 2.函数 2.1.系统函数介绍 2.2.创建.删除及调用自定义函数 3.存储过程 3.1.创建.修改及删除存储过程 3.2.调用存储过 ...
- [转]动态管理视图和函数 (Transact-SQL)
动态管理视图和函数返回可用于监视服务器实例的运行状况.诊断故障以及优化性能的服务器状态信息. 重要提示 动态管理视图和函数返回特定于实现的内部状态数据. 在未来的 SQL Server 版本中,它们的 ...
- .Net程序员学用Oracle系列:视图、函数、存储过程、包
1.视图 在实际操作过程中,本人发现 Oracle 视图定义有一个缺陷,就是不大方便注释,每次写好的注释执行之后再打开视图定义所有注释就全都没了.后来我发现把注释写到末尾就不会被清除,但这样总感觉乖乖 ...
- flask 在视图函数里操作数据库
在视图函数里操作数据库 在视图函数里操作数据的方式和在python shell中的联系基本相同,只不过需要一些额外的工作.比如把查询结果作为参数 传入模板渲染出来,或是获取表单的字段值作为提交到数据库 ...
- navicat上如何导出视图,函数等
如何导出视图,函数,一般通过linux命令行,如果简单点就用navicat把. image.png 这样函数,视图都可以导出来后续更新.....
随机推荐
- 猫哥网络编程系列:详解 BAT 面试题
从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...
- 架构之路(八)从CurrentUser说起
CurrentUser,也就是当前用户,这是我们系统中大量使用的一个概念. 确认当前用户 当然,我们利用的是cookie:用户的ID存放在cookie中,服务器端通过cookie中的Id,查找数据库, ...
- iOS开发系列--Swift进阶
概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...
- 如何在VMware中安装Windows Phone SDK 8.0 (支持模拟器调试)
相信很多开发者目前的系统还是Win7或Mac,一般不会为了开发某个程序而重装系统,所以我们就需要用到VMware这类的虚拟机来模拟预期的开发环境.在开始介绍前,给大家说明下我当前的软硬件环境,本文所讲 ...
- ABP框架 - 功能管理
文档目录 本节内容: 简介 关于 IFeatureValueStore 功能类型 Boolean 功能 Value 功能 定义功能 基本功能属性 其它功能属性 功能层次 检查功能 使用Requires ...
- pod Spec管理配置
pod Spec 为自己的项目添加pod管理功能.前言: 上一篇文章中提到,因为自己在操作的时候遇到很多坑,所在在此做一个记录,同样也希望可以帮到在这个操作上遇到坑的人. 本文将采用配图和加文字的方式 ...
- vue-router2.0 组件之间传参及获取动态参数
<li v-for=" el in hotLins" > <router-link :to="{path:'details',query: {id:el ...
- 设计模式(七): 通过转接头来观察"适配器模式"(Adapter Pattern)
在前面一篇博客中介绍了“命令模式”(Command Pattern),今天博客的主题是“适配器模式”(Adapter Pattern).适配器模式用处还是比较多的,如果你对“适配器模式”理解呢,那么自 ...
- ORACLE 11gR2 DG(Physical Standby)日常维护01
环境:RHEL 6.4 + Oracle 11.2.0.4 一.主备手工切换 1.1 主库,切换成备库并启动到mount 1.2 备库,切换成主库并启动到open 1.3 新的备库启动日志应用 二.重 ...
- 分布式系统理论基础 - 一致性、2PC和3PC
引言 狭义的分布式系统指由网络连接的计算机系统,每个节点独立地承担计算或存储任务,节点间通过网络协同工作.广义的分布式系统是一个相对的概念,正如Leslie Lamport所说[1]: What is ...