1. 简介
学习Android,自定义View不可避免,之前一直忽视这块内容,现在开始学,应该不算太晚。从常见的ViewPagerIndicator开始,当然,万能的Github上包罗万象,好用的indicator也是不胜枚举,旨在学习自定义View的一般操作过程。
2. 大致思路
做一个简单的ViewPagerIndicator,只支持平均大小的TextView,支持点,矩形和三角形。
1. 使用LinearLayout作为父类;
2. 定义indicator的颜色,高度和半径,当然也可以定义其他的属性;
3. 使用到Path,Paint,Canvas等图形绘制的内容;
4. 使用Kotlin
3. 实现
以圆形indicator为例
3.1 定义自定义属性
styles.xml
<attr name="y_indicator_color" format="color"/>
<attr name="y_indicator_radius" format="dimension"/>
<declare-styleable name="YVPDotIndicator">
<attr name="y_indicator_color"/>
<attr name="y_indicator_radius"/>
</declare-styleable>
3.2 代码实现
通过设置ViewPager,然后从Adapter的getPageTitle方法获取TextView的显示内容,然后添加标签,然后绘制圆形指示器,通过ViewPager的滑动回调方法,设置圆形指示器的位置。
class YVPDotIndicator : LinearLayout {
private var mStartPos: Float = 0.0F//indicator开始位置
private var mWidthOffset: Int = 0//初始offset
private var mPaint: Paint? = null
private var mIndicatorColor = Color.parseColor("#FFFFFF")//indicator颜色
private var mIndicatorRadius = 2//圆形indicator半径
private var mVp: ViewPager? = null
private var pageListener = InterPageChangeListener()
private var mTabCount: Int? = 0
private var mTabWidth: Float? = 0.0F
private val defaultLayoutParams = LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f)
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
setWillNotDraw(false)
val dm = resources.displayMetrics
val a = context.theme.obtainStyledAttributes(attrs, R.styleable.YVPDotIndicator, defStyle, 0)
mIndicatorRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mIndicatorRadius.toFloat(), dm).toInt()
mIndicatorColor = a.getColor(R.styleable.YVPDotIndicator_y_indicator_color, Color.parseColor("#FFFFFF"))
mIndicatorRadius = a.getDimensionPixelSize(R.styleable.YVPDotIndicator_y_indicator_radius, 2)
a.recycle()
initPaint()
}
/**
* 设置ViewPager
*/
fun setViewPager(vp: ViewPager) {
mVp = vp
if (vp.adapter == null) {
throw IllegalArgumentException()
}
notifyDataSetChanged()
mVp?.addOnPageChangeListener(pageListener)
}
fun notifyDataSetChanged() {
this.removeAllViews()
mTabCount = mVp?.adapter?.count
for (i in 0..mTabCount?.let { it - 1 } as Int) {
addTextTab(i, mVp?.adapter?.getPageTitle(i).toString())
}
}
fun addTextTab(position: Int, title: String) {
var tab = TextView(context)
tab.text = title
tab.gravity = Gravity.CENTER
tab.setSingleLine()
tab.isFocusable = true
tab.setOnClickListener { mVp?.currentItem = position }
this.addView(tab, position, defaultLayoutParams)
}
/**
* 初始化画笔
*/
private fun initPaint() {
mPaint = Paint()
mPaint?.color = mIndicatorColor
mPaint?.isAntiAlias = true
mPaint?.style = Paint.Style.FILL
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mTabWidth = (w / childCount).toFloat()
mStartPos = mTabWidth?.let { it/2 } as Float
}
override fun dispatchDraw(canvas: Canvas?) {
canvas?.save()
canvas?.translate(0.0F, height.toFloat())
canvas?.drawCircle(mStartPos + mWidthOffset, -mIndicatorRadius.toFloat(), mIndicatorRadius.toFloat(), mPaint)
canvas?.restore()
super.dispatchDraw(canvas)
}
inner class InterPageChangeListener: ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageSelected(position: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
val tabWidth = screenWidth / childCount
mWidthOffset = (tabWidth * position + tabWidth * positionOffset).toInt()
invalidate()
}
}
/**
* 获取屏幕宽度
* @return
*/
private val screenWidth: Int
get() {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
return displayMetrics.widthPixels
}
}
4. 其他Indicator
类似的矩形指示器和三角形指示器,均可按照上面的方式实现。
5. 具体效果
6. 示例源码
请移步Github———-YVPIndicator
作者:poorkick 发表于2017/7/28 13:48:44 原文链接
阅读:73 评论:0 查看评论