<Android 基础(三十七)> 自定义ViewPagerIndicator

来源:互联网 发布:淘宝卖家报复的买家 编辑:程序博客网 时间:2024/06/05 19:56

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

原创粉丝点击