前言
kotlin 的函数扩展可以给已知的任何 class 类添加函数,而不需要在写各种 utils 工具类,极大的解放了码农的天性
三大高阶用法:
type-safe builder 模式,扩展方法与扩展属性, lambda with receiver
**一、 扩展函数 **
使用 fun 来生成一个可以构建任何 Android View 的实例
inline fun <reified TV : View> v(context: Context, init: TV.() -> Unit): TV{
val constr = TV::class.java.getConstructor(Context::class.java)
val view = constr.newInstance(context)
view.init()
return view
}
/**
*<reified TV : View> reify 意为具体化。
* 而作为 kotlin 的一个方法泛型关键字,可以代表在方法体内访问泛型指定的 JVM 类对象。
* 这段代码的意思是 v 方法要使用命名为 TV(即 Type of View) 的 reified 泛型,
* 它指定类必须为 View 或其子类。
* 必须以内联的方式声明该方法才有效。调用者必须给 TV 指定一个具体的类型
*
*init: TV.() -> Unit v 方法的第二个参数是 lambda 风格的 init.
* init 是一种 lambda with receiver 类型的方法引用。是一个要求特定类型的对象的代码块,此处要求的对象在 lambda 代码中通过 this 关键字引用。这里 receiver 对象就是 reified 泛型 TV
*/
// 接下来就可以在其他 Kotlin 代码中调用这个方法来创建并初始化任何类型的 View
import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.TextView
var view = v<TextView>(context) {
layoutParams = LayoutParams(WRAP_CONTENT,WRAP_CONTENT)
text = "hello"
}
扩展 函数支持 dp-px转换
fun View.dp_f(dp: Float): Float {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,context.resources.displayMetrics)
}
fun View.dp_i(dp: Float): Int {
return dp_f(dp).toInt()
}
二、 扩展属性
对于当前已经存在的类(自定义或者Java/Android SDK 类)都可以进行动态扩展属性:
1、 为自定义类扩展属性
//自定义类
data class User(val name: String, val age: Int){}
// 为 User 类添加 gender 属性
// 声明通过 ProProxy 代理类来为 User 添加属性
var User.email: String by ProProxy()
// ProProxy class
class ProProxy {
operator fun getValue(thisRef: Any?, pro: kotlin.reflect.KProperty<*>): String {
return thisRef?.variablesMap?.get(pro.toString()) as String
}
operator fun setValue(thisRef: Any?, pro: kotlin.reflect.KProperty<*>, value: Any) {
thisRef?.variablesMap?.set(pro.toString(),value)
}
}
// 定义 ProProxy 的 variablesMap,通过 mutableMap来保存 当前对象 thisRef 的所有属性
private val Any.variablesMap by lazy {
val mutableMap: MutableMap<String, Any> = mutableMapOf()
mutableMap
}
// 现在就可以使用 User.gender 属性了
fun main(args: Array<String>) {
User().gender = "female"
}
2、为系统/SDK类扩展属性
var View.leftPadding: Int
// 指定 setter 方法,类型为 Int
set(value) {
// 通过 View.setPadding 方法设置左边距,对于其他的参数使用 Kotlin 模拟变量
setPadding(value,paddingTop,paddingRight,paddingBottom)
}
get() {
return paddingLeft
}
一个可变的扩展属性需要同时提供 getter 和 setter 方法
实战 Kotlin@Android(一):项目配置和语言转换
实战 Kotlin@Android(二):界面构建与扩展方法
实战 Kotlin@Android(三):扩展变量与其它技巧
网友评论