实现这个效果,如图:
如果不自定义控件就得像我上一篇文章那样写好多重复的代码,现在我们需要自定义一个组合控件(两个ImageView,两个TextView,一条线)。
实现
1.CommonItemLayout.kt
class CommonItemLayout : FrameLayout {
private lateinit var mIcon: ImageView
private lateinit var mTitle: TextView
private lateinit var mLable: TextView
private lateinit var mArrowIcon: ImageView
private lateinit var mLine: View
constructor(context: Context) : this(context, null)
constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
init(context, attributeSet)
}
}
继承FrameLayout,实现它的构造函数。
2.初始化view
private lateinit var mIcon: ImageView
private lateinit var mTitle: TextView
private lateinit var mLable: TextView
private lateinit var mArrowIcon: ImageView
private lateinit var mLine: View
fun getIconImageView(): ImageView {
return mIcon
}
fun init(context: Context, attributeSet: AttributeSet?) {
//添加需要用的控件
verticalLayout {
linearLayout {
minimumHeight = dip(50)
gravity = Gravity.CENTER_VERTICAL
mIcon = imageView {
imageResource = icon
}.lparams(wrapContent, wrapContent)
mTitle = textView(title) {
textColor = titleColor
textSize = titleSize
}.lparams(0, wrapContent, 1.0f) {
}
mLable = textView(lable) {
textColor = lableColor
textSize = lableSize
}.lparams(wrapContent, wrapContent)
mArrowIcon = imageView {
imageResource = arrowIcon
}.lparams(wrapContent, wrapContent)
}.lparams(matchParent, wrapContent) {
setMargins(dip(10), 0, dip(10), 0)
}
mLine = view {
backgroundColor = Color.parseColor("#cccccc")
}.lparams {
width = matchParent
height = dip(1)
setMargins(dip(15), 0, 0, 0)
}
}
//获取自定义属性
if (attributeSet != null) {
val a: TypedArray = context.obtainStyledAttributes(attributeSet, R.styleable.commonItemLayout)
icon = a.getResourceId(R.styleable.commonItemLayout_icon, 0)
title = a.getString(R.styleable.commonItemLayout_title)
titleColor = a.getColor(R.styleable.commonItemLayout_titleColor, Color.BLACK)
titleSize = a.getFloat(R.styleable.commonItemLayout_titleSize, 18f)
lable = a.getString(R.styleable.commonItemLayout_lable)
lableColor = a.getColor(R.styleable.commonItemLayout_lableColor, Color.GRAY)
lableSize = a.getFloat(R.styleable.commonItemLayout_lableSize, 14f)
hasLine = a.getBoolean(R.styleable.commonItemLayout_hasLine,true)
a.recycle()
}
}
- 定义自定义属性
4.给自定义的属性,添加set方法,并且赋值到对应的控件上
var icon: Int = 0
set(value) {
field = value
mIcon.imageResource = value
}
var title: String = ""
set(value) {
field = value
mTitle.text = title
}
var titleColor: Int = 0
set(value) {
field = value
mTitle.textColor = titleColor
}
var titleSize: Float = 0.0f
set(value) {
field = value
mTitle.textSize = titleSize
}
var lable: String = ""
set(value) {
field = value
mLable.text = lable
}
var lableColor: Int = 0
set(value) {
field = value
mLable.textColor = lableColor
}
var lableSize: Float = 0.0f
set(value) {
field = value
mLable.textSize = lableSize
}
var arrowIcon: Int = 0
set(value) {
field = value
mArrowIcon.imageResource = value
}
var hasLine:Boolean=true
set(value) {
field = value
if(value) {
mLine.visibility = View.VISIBLE
}else{
mLine.visibility = View.GONE
}
}
到这里我们可以愉快的调用了:
CommonItemLayout commonItemLayout = CommonItemLayout(context)
commonItemLayout .icon=R.mipmap.qq
commonItemLayout .title="单位设置"
...
如果你想要在Anko中使用,需要对自定义的view提供Anko支持
新建一个类专门负责注册这些自定义view,实现anko扩展
inline fun ViewManager.commonItemLayout() = commonItemLayout {}
inline fun ViewManager.commonItemLayout(
ctx: Context = AnkoInternals.getContext(this),
init: CommonItemLayout.() -> Unit
): CommonItemLayout {
return ankoView({ CommonItemLayout(ctx) }, init)
}
//你也可以你也可以扩展子控件
inline funT.mIcon(
init: ImageView.() -> Unit
): T {
getIconImageView().init()
return this
}
到此,你可以愉快的在anko使用了
commonItemLayout {
icon = R.mipmap.qq
title ="单位设置"
titleSize = 16f
titleColor = Color.DKGRAY
arrowIcon = R.mipmap.arrow_gray
onClick {
toast("单位设置")
}
}
commonItemLayout {
mIcon {
imageResource = R.mipmap.qq
}
mTitle {
text = "APP版本"
textSize = 16f
textColor = Color.DKGRAY
}
mLable {
textColor = Color.LTGRAY
textSize = 13f
text = "v.${BuildConfig.VERSION_NAME}"
}
arrowIcon = R.mipmap.arrow_gray
onClick {
toast("APP版本")
}
hasLine = false
}
在xml中使用:
到此结束,附上完整源码
class CommonItemLayout : FrameLayout {
var icon: Int = 0
set(value) {
field = value
mIcon.imageResource = value
}
var title: String = ""
set(value) {
field = value
mTitle.text = title
}
var titleColor: Int = 0
set(value) {
field = value
mTitle.textColor = titleColor
}
var titleSize: Float = 0.0f
set(value) {
field = value
mTitle.textSize = titleSize
}
var lable: String = ""
set(value) {
field = value
mLable.text = lable
}
var lableColor: Int = 0
set(value) {
field = value
mLable.textColor = lableColor
}
var lableSize: Float = 0.0f
set(value) {
field = value
mLable.textSize = lableSize
}
var arrowIcon: Int = 0
set(value) {
field = value
mArrowIcon.imageResource = value
}
var hasLine:Boolean=true
set(value) {
field = value
if(value) {
mLine.visibility = View.VISIBLE
}else{
mLine.visibility = View.GONE
}
}
private lateinit var mIcon: ImageView
private lateinit var mTitle: TextView
private lateinit var mLable: TextView
private lateinit var mArrowIcon: ImageView
private lateinit var mLine: View
constructor(context: Context) : this(context, null)
constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
init(context, attributeSet)
}
fun init(context: Context, attributeSet: AttributeSet?) {
verticalLayout {
linearLayout {
minimumHeight = dip(50)
gravity = Gravity.CENTER_VERTICAL
mIcon = imageView {
imageResource = icon
}.lparams(wrapContent, wrapContent)
mTitle = textView(title) {
textColor = titleColor
textSize = titleSize
}.lparams(0, wrapContent, 1.0f) {
}
mLable = textView(lable) {
textColor = lableColor
textSize = lableSize
}.lparams(wrapContent, wrapContent)
mArrowIcon = imageView {
imageResource = arrowIcon
}.lparams(wrapContent, wrapContent)
}.lparams(matchParent, wrapContent) {
setMargins(dip(10), 0, dip(10), 0)
}
mLine = view {
backgroundColor = Color.parseColor("#cccccc")
}.lparams {
width = matchParent
height = dip(1)
setMargins(dip(15), 0, 0, 0)
}
}
if (attributeSet != null) {
val a: TypedArray = context.obtainStyledAttributes(attributeSet, R.styleable.commonItemLayout)
icon = a.getResourceId(R.styleable.commonItemLayout_icon, 0)
title = a.getString(R.styleable.commonItemLayout_title)
titleColor = a.getColor(R.styleable.commonItemLayout_titleColor, Color.BLACK)
titleSize = a.getFloat(R.styleable.commonItemLayout_titleSize, 18f)
lable = a.getString(R.styleable.commonItemLayout_lable)
lableColor = a.getColor(R.styleable.commonItemLayout_lableColor, Color.GRAY)
lableSize = a.getFloat(R.styleable.commonItemLayout_lableSize, 14f)
hasLine = a.getBoolean(R.styleable.commonItemLayout_hasLine,true)
a.recycle()
}
}
fun getIconImageView(): ImageView {
return mIcon
}
fun getTitle(): TextView {
return mTitle
}
fun getLable(): TextView {
return mLable
}
fun getArrowIconImageView(): ImageView {
return mArrowIcon
}
}
Components.kt
inline fun ViewManager.commonItemLayout() = commonItemLayout {}
inline fun ViewManager.commonItemLayout(
ctx: Context = AnkoInternals.getContext(this),
init: CommonItemLayout.() -> Unit
): CommonItemLayout {
return ankoView({ CommonItemLayout(ctx) }, init)
}
inline funT.mIcon(
init: ImageView.() -> Unit
): T {
getIconImageView().init()
return this
}
inline funT.mTitle(
init: TextView.() -> Unit
): T {
getTitle().init()
return this
}
inline funT.mLable(
init: TextView.() -> Unit
): T {
getLable().init()
return this
}
inline funT.mArrowIcon(
init: ImageView.() -> Unit
): T {
getArrowIconImageView().init()
return this
}