PageIndicatorView滑动指示器

3 篇文章 0 订阅
2 篇文章 0 订阅

相信大家可能都用过滑动指示器,开源的也有很多种,最近项目中有遇到过,于是自己写了一个。

前期思想:

1. 肯定要满足左右滑动定位

2. 肯定要满足动态定位索引,设置page个数

3. 要支持自定义的dot选中和未选中drawable

4. 要支持最大显示dot数目。数据不足与数据溢出的处理

5. 如果数据数目>最大显示dot数,如果处理显示更多 ,这是个难点 

解决方案:

1. 左右预留1个dot,滑动的时候表示更多,但是滑到边界要定位到这个dot

2. 如何解决在左右边界滑动过程来回滑动的定位问题

 

开发实现:

1. 自定义属性

    <declare-styleable name="PageIndicatorView">
        <attr name="maxDots" format="integer"/>
        <attr name="space" format="integer"/>
        <attr name="unselected" format="reference"/>
        <attr name="selected" format="reference"/>
    </declare-styleable>

 

2. 代码实现:
 

package com.ljx.widget.common

import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.widget.LinearLayout
import com.ljx.widget.R

/**
 * pagerIndicator
 *
 * 滑动指示器
 * 可以设置最大显示dot数
 * 可以设置总数count
 * 当maxDots<totalCount 会预留边界1个dot代表更多
 * 当maxDots>=totalCount 会显示totalCount个dot
 * 可见dot = Math.min(maxDots,totalCount)
 * @author liangjianxiong
 * @date 19/5/23
 */
class PageIndicatorView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {

    //可见dot数
    private var visibleDots = 0
    //最大dot设置数
    private var maxDots = 5
    //dot间距
    private var marginSpace = 6
    //实际总数
    private var totalSize = 0
    //dot views
    private var indicatorViews: ArrayList<View>? = null
    //当前索引
    private var currentIndex = 0
    //历史索引
    private var preIndex = 0
    //当前可见索引
    private var curVisibleIndex = -1
    //历史可见索引
    private var preVisibleIndex = -1
    //未选择资源id
    private var unselectedId = -1
    //选中资源id
    private var selectedId = -1

    constructor(context: Context?) : this(context, null)

    init {
        gravity = Gravity.CENTER
        orientation = HORIZONTAL
        val typeArray = getContext().obtainStyledAttributes(attrs, R.styleable.PageIndicatorView, 0, 0)
        maxDots = typeArray.getInt(R.styleable.PageIndicatorView_maxDots, maxDots)
        marginSpace = typeArray.getInt(R.styleable.PageIndicatorView_space, marginSpace)
        unselectedId = typeArray.getResourceId(
            R.styleable.PageIndicatorView_unselected,
            R.drawable.dot_unselected
        )

        selectedId = typeArray.getResourceId(
            R.styleable.PageIndicatorView_selected,
            R.drawable.dot_selected
        )
    }

    private fun initIndicator(size: Int) {
        if (indicatorViews == null) {
            indicatorViews = ArrayList()
        } else {
            indicatorViews!!.clear()
            removeAllViews()
        }
        if (size <= 0) return
        totalSize = size
        visibleDots = Math.min(maxDots,totalSize)

        for (i in 0 until visibleDots) {
            val view = View(context)
            val params =
                LinearLayout.LayoutParams(18, 2)
            if (i == 0) {
                params.setMargins(0, 0, 0, 0)
            } else {
                params.setMargins(marginSpace, 0, 0, 0)
            }
            view.setBackgroundResource(unselectedId)
            addView(view, params)
            indicatorViews!!.add(view)
        }
    }

    /**
     * set 最大可见dot数
     */
    fun setMaxVisiableCount(count: Int) {
        maxDots = count
        setCount(totalSize)
    }

    /**
     * set total count
     */
    fun setCount(size: Int) {
        initIndicator(size)
        setSelect(0)
    }

    /**
     * set select dot
     * 这里定位逻辑有点小复杂
     * 看代码难以理解 建议看UI效果
     * 左右预留1个dot代表未到达边界,但是来回滑动可以在[1~size-2]之间来回滚动
     */
    fun setSelect(index: Int) {
        if (currentIndex < 0 || currentIndex >= totalSize || indicatorViews == null || (indicatorViews!=null && indicatorViews!!.size == 0)) {
            return
        }
        preIndex = currentIndex
        currentIndex = index
        preVisibleIndex = curVisibleIndex
        if(currentIndex>=preIndex){
            //→️右滑
            if(maxDots>=totalSize){
                curVisibleIndex = currentIndex
                setCurrentVisableIndex(curVisibleIndex)
            }else{
                if(currentIndex == totalSize -1){
                    curVisibleIndex = visibleDots-1
                    setCurrentVisableIndex(curVisibleIndex)
                }else{
                    curVisibleIndex = preVisibleIndex+1
                    if(curVisibleIndex>=visibleDots-1){
                        curVisibleIndex = preVisibleIndex
                    }
                    setCurrentVisableIndex(curVisibleIndex)
                }
            }
        }else if(currentIndex<preIndex){
            //⬅左滑
            if(maxDots>=totalSize){
                curVisibleIndex = currentIndex
                setCurrentVisableIndex(curVisibleIndex)
            }else{
                if(currentIndex == 0){
                    curVisibleIndex = 0
                    setCurrentVisableIndex(curVisibleIndex)
                }else{
                    curVisibleIndex = preVisibleIndex-1
                    if(curVisibleIndex<1){
                        curVisibleIndex = preVisibleIndex
                    }
                    setCurrentVisableIndex(curVisibleIndex)
                }
            }
        }
    }

    private fun setCurrentVisableIndex(visibelIndex: Int) {
        if(visibelIndex>=0 && visibelIndex<visibleDots){
            if(preVisibleIndex>=0 && preVisibleIndex<visibleDots){
                indicatorViews!!.get(preVisibleIndex).setBackgroundResource(unselectedId)
            }
            if(curVisibleIndex>=0 && curVisibleIndex<visibleDots){
                indicatorViews!!.get(curVisibleIndex).setBackgroundResource(selectedId)
            }
        }
    }

}

 

3. 布局使用

        <com.ljx.widget.common.PageIndicatorView
                android:layout_centerHorizontal="true"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="10dp"
                android:id="@+id/pageIndicatorView"
                app:selected="@drawable/dot_selected"
                app:unselected="@drawable/dot_unselected"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

4. 代码使用:

//设置可见最大dot数
pageIndicatorView.setMaxVisiableCount(6)
//设置数据总数
pageIndicatorView.setCount(100)
//定位position
pageIndicatorView.setSelect(position)


效果图:

 

总结:

1.  边界滑动的时候dot跟随动画
2. dot的大小目前是写死的,因为暂时项目用到,还没有支持设置点的大小
后续有时间了会更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值