开篇
继上篇,本篇教你如何用 Kotlin+Anko 更简洁地自定义控件。假如我们需要定义效果如下的控件:
一个横向的LinearLayout包含三个子控件:ImageView、TextView、ImageView。
- 1、自定义控件,代码很简单,MyItemLayout.kt:
open class MyItemLayout : LinearLayout {
private lateinit var iconView: ImageView
private lateinit var labelView: TextView
private lateinit var arrowView: ImageView
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
private fun init() = apply{
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER_VERTICAL
//icon
iconView = imageView(){
imageResource = R.drawable.kit_ic_assignment_blue_24dp
}
iconView.layoutParams = LayoutParams(wrapContent, wrapContent)
//label
labelView = textView {
textSize = 14f
textColor = 0xFF333333.toInt()
leftPadding = dip(12)
rightPadding = dip(12)
}
labelView.layoutParams = LayoutParams(0, wrapContent, 1.0f)
//arrow
arrowView = imageView(){
imageResource = R.drawable.kit_ic_chevron_right_gray_24dp
}
arrowView.layoutParams = LayoutParams(wrapContent, wrapContent)
}
fun getIconView(): ImageView {
return iconView
}
fun getLabelView(): TextView {
return labelView
}
fun getArrowView(): ImageView {
return arrowView
}
}
说明:
private lateinit var iconView: ImageView
private lateinit var labelView: TextView
private lateinit var arrowView: ImageView
我们并不希望外部使用者替换我们这三个view,所以都设置成private
访问权限。又因为是lateinit
属性,所以我们不能在属性下面添加get和set方法。如果要提供外部直接访问这三个view,我们自行添加get方法。
lateinit' modifier is not allowed on properties with a custom getter or setter
- 2、给MyItemLayout添加扩展内联方法,方便以Anko语法调用。MyItemLayoutExtend.kt:
import android.content.Context
import android.view.ViewManager
import android.widget.ImageView
import android.widget.TextView
import jsc.kit.itemlayout.MyItemLayout
import org.jetbrains.anko.custom.ankoView
import org.jetbrains.anko.internals.AnkoInternals
inline fun ViewManager.myItemLayout(
ctx: Context = AnkoInternals.getContext(this),
theme: Int = 0,
init: MyItemLayout.() -> Unit
): MyItemLayout {
return ankoView({ MyItemLayout(ctx) }, theme, init)
}
//icon
inline fun <T : MyItemLayout> T.ilIcon(
init: ImageView.() -> Unit
): T {
getIconView().init()
return this
}
//label
inline fun <T : MyItemLayout> T.ilLabel(
init: TextView.() -> Unit
): T {
getLabelView().init()
return this
}
//arrow
inline fun <T : MyItemLayout> T.ilArrow(
init: ImageView.() -> Unit
): T {
getArrowView().init()
return this
}
说明:
inline fun ViewManager.myItemLayout(
ctx: Context = AnkoInternals.getContext(this),
theme: Int = 0,
init: MyItemLayout.() -> Unit
): MyItemLayout {
return ankoView({ MyItemLayout(ctx) }, theme, init)
}
ctx
——Context 。我们初始化为AnkoInternals.getContext(this)
返回的值
theme
—— Int。我们初始化为0
init
—— block块。我们把block的作用域限制在MyItemLayout的对象内
如果非block参数有初始化值,在调用时可以不传
同理我们再来看看上面的ilLabel扩展:
inline fun <T : MyItemLayout> T.ilLabel(
init: TextView.() -> Unit
): T {
getLabelView().init()
return this
}
我们只定义了一个参数init
block,其作用域是TextView,我们用来配置MyItemLayout中的labelView
。
getLabelView().init()
大概意思就是:让MyItemLayout中的labelView
执行init
这块代码。
我们可以这样写,让init
没有作用域,仅仅是一个block块:
inline fun <T : MyItemLayout> T.ilLabel(
init: () -> Unit
): T {
init()
return this
}
- 3、在Anko中使用MyItemLayout:
myItemLayout {
leftPadding = dip(16)
rightPadding = dip(16)
topPadding = dip(8)
bottomPadding = dip(8)
backgroundResource = R.drawable.xxx
}.ilIcon {
imageResource = R.drawable.xxx
}.ilLabel {
text = "I'am JustinEoy"
textColor = Color.BLUE
textSize = 15f
}.ilArrow {
imageResource= R.drawable.xxx
alpha = 0.4f
}
源码
源码传送门——https://github.com/JustinRoom/MyKotlinAnko/blob/master/library/src/main/java/jsc/kit/itemlayout
篇尾
如果觉得我写得不错的点个爱心吧,也顺便加个关注啦!我是JustinRoom, QQ:10063682252。