今天要來看看我們可以透過 Extensions 做到什麼,在開始前要先了解什麼是 Extensions ,以下如有解釋不清或是描述錯誤的地方還請大家多多指教:
在不需要繼承以及使用任何 design pattern 來擴充原有的 class 或是 interface 的前提下,Koltin 提供了一個可以擴充新方法或屬性,且不會改變 class 或 interface 本身的內容物。
針對一個既有的 class 建立 Extension Function ,那個 class 的 name 會在前綴當作 receiver type,就如下面的範例,假如今天想針對 ImageView 的 class 擴充一個設定灰階的方法:
// 這邊有用到 funciotn type
fun ImageView.setGreyColorScale(condition: () -> Boolean) {
ColorMatrix().also {
it.setSaturation(0f) //0 means grayscale
val colorFilter = ColorMatrixColorFilter(it)
this.colorFilter = if (condition()) colorFilter else null
// 'this' 是接收的 imageView
}
}
// 實際應用
productImageView.setGreyColorScale { a > 0 }
// or
fun ImageView.setGreyColorScale(isNeedGrey: Boolen) {
ColorMatrix().also {
it.setSaturation(0f) //0 means grayscale
val colorFilter = ColorMatrixColorFilter(it)
this.colorFilter = if (isNeedGrey) colorFilter else null
// 'this' 是接收的 imageView
}
}
// 實際應用
productImageView.setGreyColorScale(a > 0)
除此之外需要避免和既有的 function 同名,除非是不同 arguments overload 原有的 function:
class Example {
fun printFunctionType() { println("Class method") }
}
fun Example.printFunctionType(i: Int) { println("Extension function #$i") }
Example().printFunctionType(1)
// get Extension function #1
如果想要一個通用型態的 function,泛型也可以做擴充:
fun <T> MutableList<T>.clearAndAddAll(replace: MutableList<T>) {
clear()
addAll(replace)
}
因為 extensions 並不是真的 insert 任何參數或方法在 class 中,extension property 並不會有 backing field,所以屬性不能初始化:
val <T> List<T>.lastIndex: Int
get() = size - 1
// e.g. val <T> List<T>.lastIndex: Int = 1
// error: initializers are not allowed for extension properties
companion object 因為沒有命名,所以擴充的名稱為 Companion,呼叫時可只用 class 名稱當 receiver。
class ExampleClass {
companion object { } // will be called "Companion"
}
fun ExampleClass.Companion.printName() { println("companion") }
fun main() {
ExampleClass.printName()
}
通常我會把較常做的事情或是通用的事情變成 Extension Function,像是需要動態更改元件的 margin 或 padding 時,我們需要做 type 的轉換。
fun Float.toPx() = this * Resources.getSystem().displayMetrics.density
fun Float.toDp() = this / Resources.getSystem().displayMetrics.density
大部分會將 function 定義在最高層級,直接寫在檔案的 package name 下,在這邊我會建立一個空的檔案就取名 CommonExtensions: