原來今天才是周六~那就今天水
自定義view怎么實現(xiàn),我今天不想多說,畢竟也不是給新人看的。
那么今天直接講一些實現(xiàn)自定義view的小技巧吧。
本期舉例的自定義view只是拋磚引玉,隨手寫的沒有經(jīng)過測試,如果想使用一定要三思而后行~
1.利用databinding或者viewbinding,告別如下代碼~
animView = findViewById(R.id.anim_view)
iconView = findViewById(R.id.iv_tab)
textView = findViewById(R.id.tv_tab)
badgeView = findViewById(R.id.iv_badge)
那么我們直接看優(yōu)化后的代碼~
private val mBinding by lazy {
ViewMainBottomLayoutBinding.inflate(
LayoutInflater.from(context),
this,
true
)
}
mBinding.tvTab.xxxxxxxx
//直接使用,節(jié)省時間。
- 讓你的自定義view支持style,方便使用
首先看我們的自定義屬性
<declare-styleable name="BottomNavigationView">
<attr name="iconWidth" format="dimension" />
<attr name="iconHeight" format="dimension" />
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
</declare-styleable>
然后定義默認style
<style name="BottomNavigationViewStyle">
<item name="iconWidth">30dp</item>
<item name="iconHeight">30dp</item>
<item name="textColor">@color/color_bottom_nav_view_text_default</item>
<item name="textSize">12sp</item>
</style>
在創(chuàng)建view的構(gòu)造函數(shù)中填入默認style,然后其他與正常寫自定義view就一樣啦~
constructor(context: Context, attrs: AttributeSet?) : super(
context,
attrs,
R.style.BottomNavigationViewStyle
) {
setupAttr(attrs)
}
如果我們想動態(tài)加入主題呢?可以在自定義view中添加setTheme方法,然后取值方式如下,可能還有其他取值方式~不過懶得找了。
fun setTheme(themeId: Int) {
val mTheme = context.resources.newTheme()
mTheme.applyStyle(themeId, true)
mTheme.obtainStyledAttributes(
intArrayOf(
R.attr.iconWidth,
R.attr.iconHeight,
R.attr.textColor,
R.attr.textSize
)
).run {
iconWidth =
this.getDimensionPixelSize(this.getIndex(0), iconWidth)
iconHeight =
this.getDimensionPixelSize(this.getIndex(1), iconHeight)
textColor =
this.getColorStateList(this.getIndex(2)) ?: textColor
textSize = this.getDimension(this.getIndex(3), textSize)
recycle()
}
setup()
}
如此,我們便可以直接配置style給自定義view啦~由于本demo使用的是組合view,所以我們可以在父view中接受自定義參數(shù)例如:
<declare-styleable name="BottomNavigationGroup">
<attr name="navBottomViewStyle" format="reference" />
</declare-styleable>
然后獲?。?/p>
context.obtainStyledAttributes(attrs, R.styleable.BottomNavigationGroup).run {
navViewThemeId =
getResourceId(R.styleable.BottomNavigationGroup_navBottomViewStyle, navViewThemeId)
recycle()
}
之后在Build子view時,將themeId傳入即可~
當然,寫法有很多,本篇僅僅是拋磚引玉而已。
- dsl構(gòu)建view參數(shù)
先看效果~ 可以是這樣的
mBinding.homeTab.setup {
options(
bottomNavOption {
id { R.id.home }
tabText { "home" }
iconRes { R.drawable.ic_main_nav_home }
},
bottomNavOption {
id { R.id.topic }
tabText { "topic" }
iconRes { R.drawable.ic_main_nav_home }
},
bottomNavOption {
id { R.id.find }
tabText { "find" }
iconRes { R.drawable.ic_main_nav_home }
},
bottomNavOption {
id { R.id.me }
tabText { "me" }
iconRes { R.drawable.ic_main_nav_home }
}
)
listener {
object : BottomNavigationGroup.OnCheckedChangeListener {
override fun onCheckedChanged(group: BottomNavigationGroup?, checkedId: Int) {
}
}
}
defaultChecked {
R.id.home
}
}
也可以是這樣的~
mBinding.homeTab.setup {
options(
bottomNavOption {
id { R.id.home }
tabText { "home" }
iconRes { R.drawable.ic_main_nav_home }
})
options(bottomNavOption {
id { R.id.topic }
tabText { "topic" }
iconRes { R.drawable.ic_main_nav_home }
})
options(
bottomNavOption {
id { R.id.find }
tabText { "find" }
iconRes { R.drawable.ic_main_nav_home }
})
bottomNavOption {
id { R.id.me }
tabText { "me" }
iconRes { R.drawable.ic_main_nav_home }
}
)
listener {
object : BottomNavigationGroup.OnCheckedChangeListener {
override fun onCheckedChanged(group: BottomNavigationGroup?, checkedId: Int) {
}
}
}
defaultChecked {
R.id.home
}
}
當然,寫法有很多,本文最終提交的是第一種的寫法~
這個dsl看起來復(fù)雜,其實很簡單,例如option構(gòu)建時我們多寫一些方法~
class Option {
@IdRes
var id: Int = -1
private set
var tabText: String = ""
@DrawableRes
var iconRes: Int = 0
private set
var textColor: ColorStateList? = null
private set
var iconW: Int = 0
private set
var iconH: Int = 0
private set
var textSize: Float = 0f
private set
fun id(init: () -> Int) {
id = init()
}
fun tabText(init: () -> String) {
tabText = init()
}
fun iconRes(init: () -> Int) {
iconRes = init()
}
fun textColor(init: () -> Int) {
textColor = ResourceUtil.getColorStateList(resId = init())
}
fun iconW(init: () -> Int) {
iconW = init()
}
fun iconH(init: () -> Int) {
iconH = init()
}
fun textSize(init: () -> Float) {
textSize = init()
}
}
這樣就可以使用高階函數(shù)進行構(gòu)建了,配合kotlin的lambda特性即可達到效果~
當然,為了看起來更舒適,也少不了我們的擴展函數(shù)啦~
fun bottomNavOption(init: BottomNavigationView.Option.() -> Unit): BottomNavigationView.Option {
val option = BottomNavigationView.Option()
option.init()
return option
}
至此,我們便完成了一個優(yōu)雅的自定義view