系列文章目录
自定义view实现
文章目录
前言
在模仿荣耀手机上的天气App时,天气界面底部的指示器小圆点用原生TabLayout控件实现较为复杂,于是自己用自定义view的方式简单实现了一个。
提示:以下是本篇文章正文内容,下面案例可供参考
一、实现方案
1. 原理
确定ViewPager2包含fragment的总数量和fragment当前的位置,切换页面时重新绘制指示器样式。
2. 直接继承 view的方式,复杂度不高,只需要重写onMeasure方法和onDraw方法。
onMeasure方法中实现了根据控件宽高和指示器个数动态计算圆点的直径
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
mIndicatorWidth = MeasureSpec.getSize(widthMeasureSpec)
mIndicatorHeight = MeasureSpec.getSize(heightMeasureSpec)
// item宽度 = 指示器宽度 / (item个数 + 间隔个数)
mItemWidth = mIndicatorWidth.div(mIndicatorItemCount + mIndicatorItemCount - 1)
// item高度 = item宽度和指示器高度中的小值,避免绘制不全
mItemHeight = mItemWidth.coerceAtMost(mIndicatorHeight)
// 绘制item的起始位置 = 指示器宽度/2 - 绘制区域/2,保持绘制区域居中显示
mStartPos =
mIndicatorWidth.div(2f) - ((mIndicatorItemCount + mIndicatorItemCount - 1) * mItemHeight).div(
2f
)
// 不需要改变原控件大小,此处不需要重绘
// setMeasuredDimension(mIndicatorWidth, mIndicatorHeight)
}
这里绘制的是圆点指示器,其余形状的大家有兴趣可以自己实现。
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val dy = mIndicatorHeight.div(2f)
// 圆半径
val cr = mItemHeight.div(2f)
for (i in 0 until mIndicatorItemCount) {
// 指示器为圆形
mIndicatorItemDistance = mItemHeight
// 动态计算每个item的起始绘制位置
val dx = mStartPos + i * mItemHeight + i * mIndicatorItemDistance + cr
// item选中态在大小和颜色上有所不同
canvas.drawCircle(
dx,
dy,
if (i == mCurrentSelectedPosition) cr else cr.div(1.5f)