不出所料这再次体现了Java编码的尾大不掉,简简单单的功能在Java代码中被分解为以下几个专门的处理:
1、首先要定义一个数组适配器ArrayAdapter,指定待选择的字符串数组,以及每项文本的布局文件;
2、其次要定义一个选择监听器OnItemSelectedListener,在用户选中某项时触发,响应文本项的选中事件;
3、最后Spinner控件依次设置选择对话框的标题、数组适配器、选择监听器、默认选项等等;
我的天,这也太专业了吧,在产品经理看来,这只是个下拉框而已,有必要搞这么复杂吗?然而Java代码就是这么错综复杂,要想开发Android,只能这么捣腾,不然还有更好的法子吗?不信的话换成Kotlin试试?说时迟那时快,在Android Studio上面把Spinner上述的Java代码转换为Kotlin,不一会儿就生成了如下的Kotlin代码:
private fun initSpinner() {
val starAdapter = ArrayAdapter(this, R.layout.item_select, starArray)
starAdapter.setDropDownViewResource(R.layout.item_dropdown)
val sp = findViewById(R.id.sp_dialog) as Spinner
sp.prompt = "请选择行星"
sp.adapter = starAdapter
sp.setSelection(0)
sp.onItemSelectedListener = MySelectedListener()
}
private val starArray = arrayOf("水星", "金星", "地球", "火星", "木星", "土星")
internal inner class MySelectedListener : OnItemSelectedListener {
override fun onItemSelected(arg0: AdapterView<*>, arg1: View, arg2: Int, arg3: Long) {
toast("你选择的行星是${starArray[arg2]}")
}
override fun onNothingSelected(arg0: AdapterView<*>) {}
}
瞧瞧,号称终结者的Kotlin也不过尔尔,整体代码量跟Java相比是半斤八两,丝毫不见了往日的威风。由于这里的Java代码逻辑实在拐弯抹角,又是数组适配器又是选择监听器的,因此Kotlin对这种玩意确实没有好办法。既然此路不通,那就试试别的办法呗,前面提到Spinner其实由两部分组成,一部分是直接显示在界面上的带箭头文本,另一部分是点击后弹出的选择对话框,所以能不能绕过Spinner,运用所见即所得的理念,干脆把下拉框分离成两个控件好了。倘若仅仅是一个带箭头的文本,毫无疑问使用文本视图TextView就可以了,箭头图标可以在布局文件中通过drawableRight属性来指定。于是布局文件中的下面Spinner节点:
<Spinner
android:id="@+id/sp_dialog"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/tv_dialog"
android:gravity="left|center"
android:spinnerMode="dialog" />
表面上完全可以被下面这个TextView节点所取代:
<TextView
android:id="@+id/tv_spinner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/tv_dialog"
android:gravity="center"
android:drawableRight="@drawable/arrow_down"
android:textColor="@color/black"
android:textSize="17sp" />
如果再来一个选择对话框,这样只要给该文本视图添加点击事件,点击TextView弹出选择框,岂不是万事大吉?正巧Anko库已经提供了这股东风,与alert一样来自于Context的扩展函数,它便是“selector(对话框标题, 字符串队列) { i -> 第i项的选中处理代码 }”,那么将其与前面的文本视图相结合,即可无缝实现原来的下拉框功能,具体的Kotlin代码如下所示:
val satellites = listOf("水星", "金星", "地球", "火星", "木星", "土星")
tv_spinner.text = satellites[0]
tv_spinner.setOnClickListener {
selector("请选择行星", satellites) { i ->
tv_spinner.text = satellites[i]
toast("你选择的行星是${tv_spinner.text}")
}
}
看看这几行代码,完全不见了数组适配器和选择监听器的踪影,故而代码量一下剧减到对应Java代码的三分之一。当然,为了正常地使用selector函数,不要忘了在代码文件头部加上下面一行导入语句:
import org.jetbrains.anko.selector
虽然把布局文件里面的Spinner控件换成TextView,但是二者在功能使用上是没什么区别的,同样支持点击文本弹出选择框,也同样支持选中某项的回调。改造后下拉框的界面效果如下图所示。
如此方便易用的selector,竟然撇开了数组适配器和选择监听器,那么它又是怎么实现的呢?认真阅读Anko库里面的selector源码,发现原来该函数利用了AlertDialog的setItems方法,通过setItems方法指定一串文本,并且定义了每项的点击事件,其运行结果竟