Kotlin基础 — 扩展函数

592 阅读2分钟

概述

扩展函数:指在一个类上增加一种新的行为,甚至我们没有这个类代码的访问权限。类似Java中很多带有static方法的工具类。

优势:不需要在调用方法的时候把整个对象当作参数传入。而是像是属于扩展类的一样,可以使用this关键字和调用所有public方法。


应用场景

参考anko-common 依赖包中ContextUtils、Dialogs 等文件的写法

// 属性扩展
// 注意:anko-common包中没有扩展V4包中的Fragment,需要自己扩展,否则无法获取到ctx属性
val Fragment.ctx: Context
    get() = activity

// 属性扩展
val Context.ctx: Context
    get() = this

// 函数扩展
inline fun <reified T : View> Activity.find(id: Int): T = findViewById(id) as T
inline fun <reified T : View> Fragment.find(id: Int): T = view?.findViewById(id) as T

// 函数扩展
fun Context.toast(textResource: Int) = Toast.makeText(this, textResource, Toast.LENGTH_SHORT).show()
fun Context.toast(text: CharSequence) = Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
inline fun AnkoContext<*>.longToast(textResource: Int) = ctx.longToast(textResource)
// ...略...

1. 属性的扩展

val Fragment.ctx: Context
    get() = activity

public var TextView.text: CharSequence
    get() = getText()
    set(v) = setText(v)

2. 函数的扩展

fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}


应用

扩展EditText的TextWatcher监听

fun EditText.beforeTextChanged(action: (s: CharSequence?, start: Int, count: Int, after: Int)->Unit) = textWatch(before = action)

fun EditText.onTextChanged(action: (s: CharSequence?, start: Int, count: Int, after: Int)->Unit) = textWatch(change = action)

fun EditText.afterTextChanged(action: (s: Editable?)->Unit) = textWatch(after = action)


fun EditText.textWatch(
        before: ((s: CharSequence?, start: Int, count: Int, after: Int)->Unit)? = null,
        change: ((s: CharSequence?, start: Int, before: Int, count: Int)->Unit)? = null,
        after:  ((s: Editable?) -> Unit)? = null
) : EditText {

    return apply { // 这里返回EditText
        val listener = object : TextWatcher{
            override fun afterTextChanged(s: Editable?) {
                after?.invoke(s)
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                before?.invoke(s, start, count, after)
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                change?.invoke(s, start, before, count)
            }

        }
        addTextChangedListener(listener)
    }
}

使用

class JokeListFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater?.inflate(R.layout.joke_fragment_joke_list, null)
        return view
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
       
        // 实现链式调用
        editText.beforeTextChanged {
            s, start, count, after -> Log.d("Joke", "before =$s")

        }.onTextChanged {
            s, start, count, after -> Log.d("Joke", "change =$s")

        }.afterTextChanged {
            s -> 
            Log.d("Joke", "after =${s.toString()}")
            toast(s.toString())
        }
    }

}