借助 with 的神力
看到上一篇文章对 with
的解析,你是不是想到什么?with
简直就是为 Builder
模式而生的。
我们尝试构建一个 PopupWindow
,下面是我们部分需要的东西(可自定义的参数):
context
layoudId
width
listener //为popupWindow的某些view设置点击事件复制代码
我们的 Builder
类如下:
class PopupWindowGen (private val context: Context) {
@LayoutRes
var layoutId = 0
var width = 100
//设置监听器需要知道view的id和对应的响应事件,这里用 Pair 把他们包起来
private val listeners: MutableList<Pair<Int, (View) -> Unit>> = mutableListOf()
fun addListener(@IdRes id: Int, body: (View) -> Unit) {
listeners.add(Pair(id, body))
}
fun build(): PopupWindow {
val popView = LayoutInflater.from(context).inflate(layoutId, null, false)
listeners.forEach {
val view = popView.findViewById<View>(it.first)
view.setOnClickListener { v -> it.second(v) }
}
val popupWindow = PopupWindow(popView, width, ViewGroup.LayoutParams.WRAP_CONTENT, true)
return popupWindow
}
}复制代码
这样,一个简单的 Builder
就编写完毕了,我们可以像下面一样构造出对象了:
val popupWindow = with(PopupWindowGen(context)) {
layoutId = R.layout.popup_window
width = 200
addListener(R.id.btn, { print(it) })
addListener(R.id.tvm { print(it) })
build()
}复制代码
优化
我们发现其实上面代码还是有点怪怪的,我们想要的是:
val popupWindow = PopupWindowGen.generate(context) {
...
}复制代码
我们在 PopupWindowGen
里面再写一个静态方法,同时将构造方法私有化:
class PopupWindowGen (private val context: Context) {
companion object {
fun generate(context: Context, body: PopupWindowGen.() -> PopupWindow): PopupWindow {
return with(PopupWindowGen(context)) {
body()
}
}
}
...
}复制代码
大功告成:
val popupWindow = PopupWindowGen.with(context) {
layoutId = R.layout.popup_window
width = 200
addListener(R.id.btn, { print(it) })
addListener(R.id.tvm { print(it) })
build()
}复制代码
快动手试试吧~
———
技术上的问题,欢迎讨论。
最近在 Github 上维护的项目:
- LiteWeather [一款用 Kotlin 编写,基于 MD 风格的轻量天气 App],对使用 Kotlin 进行实际开发感兴趣的同学可以看看,项目中会使用到 Kotlin 的委托机制、扩展机制和各种新奇的玩意。
- LiteReader [一款基于 MD 的极轻阅读 App,提供知乎日报、豆瓣电影等资源],项目主要使用了 MVVM 设计模式,界面遵循 Material Design 规范,提供轻量的阅读体验。
- LiveMVVM [Kotlin 编写的 Android MVVM 框架,基于 android-architecture],轻量 MVVM+Databinding 开发框架。
- AnkoUtil [Kotlin 编写的 Android 扩展库]。
欢迎 star/fork/follow 提 issue 和 PR。