Android ViewPager Indicator 一个图片轮播指示器

一、效果

切换方式:

目前有四种切换方式
1、直接切换

直接切换.gif

2、渐变
渐变.gif

3、滑动
滑动.gif

4、滚动
滚动.gif

四种形状:

圆形、正方形、菱形、三角形(若选择菱形滚动模式因动效半径问题,默认效果为滑动)

二、用法

1、在项目中app的build.gralde中添加

implementation 'com.chz.view:guide:1.2'

2、在需要用到指示器的父布局文件下
注意
合理设置指示器数量、尺寸、间距

    <com.chz.guide.view.GuideView
        android:id="@+id/circle_change_guide"
        android:layout_width="wrap_content"//参数被屏蔽,失效
        android:layout_height="wrap_content"//参数被屏蔽,失效
        app:changeMode="change"//切换模式,不声明默认为'改变'
        app:distanceSize="50dp"//指示器之间的距离(大于等于0)
        app:focusColor="#FF0000"//选中指示器颜色
        app:guideShape="circle"//指示器形状,不声明默认为'圆形'
        app:indexCount="4"//指示器数量(大于等于0)
        app:indexSize="50dp"//指示器尺寸(大于0)
        app:normalColor="#0000FF"//非选中指示器颜色
    />

3、在你的Activity或者Fragment中

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circle_alpha);
        //找到Viewpager控件
        viewPager = findViewById(R.id.circle_alpha_vp);
        //找到指示器控件
        guideView = findViewById(R.id.circle_alpha_guide);
        //Viewpager适配器初始化
        PagerAdapter adapter = new GuideAdapter(this);
        //设置适配器
        viewPager.setAdapter(adapter);
        //调用GuideView的addOnPageChangeListener方法,将Viewpager作为参数传进去
        guideView.addOnPageChangeListener(viewPager);
        //主动设置当前ViewPager position
        guideView.updatePosition(position);
    }

三、源码解读

1、架构

两个重点:形状、切换效果

代码架构.png

2、自定义的GuideView

1.自定义View xml资源文件
形状和切换模式使用枚举来表示,并且为了避免魔鬼数字,均为两位数

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="indexSize" format="dimension" />
    <attr name="distanceSize" format="dimension" />
    <attr name="indexCount" format="integer" />
    <attr name="focusColor" format="color" />
    <attr name="normalColor" format="color" />
    <attr name="guideShape">
        <enum name="circle" value="11" />
        <enum name="square" value="22" />
        <enum name="diamond" value="33" />
        <enum name="triangle" value="44" />
    </attr>
    <attr name="changeMode">
        <enum name="change" value="11" />
        <enum name="alpha" value="22" />
        <enum name="slide" value="33" />
        <enum name="scroll" value="44" />
    </attr>
    <declare-styleable name="GuideView">
        <attr name="indexSize" />
        <attr name="distanceSize" />
        <attr name="indexCount" />
        <attr name="focusColor" />
        <attr name="normalColor" />
        <attr name="guideShape" />
        <attr name="changeMode" />
    </declare-styleable>
</resources>

2.GuideView类
GuideView仅作为一个承载容器,负责形状基础参数的初始化和边界合法性判断

 public GuideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
       ······
        initShape();
        //指示器参数初始化
        shape.baseInit(changeMode, indexShape,normalColor, focusColor, indexSize,
                distanceSize, indexCount, scrollCount);
    }
//判断指示器控件是否超出父容器边界
    private void checkViewSize() {
         ······
    }

在GuideView中初始化控件尺寸
宽度=指示器宽度*指示器数量+指示器间距*指示器间距数量
高度分两种情况
滚动模式下:
正方形的最大高度为对角线长度,三角形最大高度为边长,剩余两种形状高度与非滚动模式下相同。
非滚动模式下:
圆形、正方形、菱形的高都为指示器宽度,而形状为三角形,控件的高则为当前正三角形的高。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        viewWidth = (int) (indexCount * (indexSize + distanceSize) - distanceSize);
        viewHeight = (int) indexSize;
        switch (indexShape) {
            case SHAPE_CIRCLE:
                break;
            case SHAPE_SQUARE:
                if (changeMode == MODE_SCROLL) {
                    viewHeight = (int) (indexSize / Math.cos(45 *PI));
                }
                break;
            case SHAPE_DIAMOND:
                break;
            case SHAPE_TRIANGLE:
                if (changeMode != MODE_SCROLL) {
                    viewHeight = (int) (indexSize / 2 * Math.tan(60 * PI));
                }
                break;
            default:
                break;
        }
        setMeasuredDimension(viewWidth, viewHeight);
    }

3.GuideShape类
GuideShape是一个抽象类,实现了ViewPager的滑动监听方法,负责所有形状的公共参数初始化,形状切换状态也实现的ViewPager滑动监听方法中实现。

public abstract class GuideShape implements ViewPager.OnPageChangeListener {
    ······
    public void baseInit(int mode, int shape, int normalColor, int focusColor
            , float indexSize, float distanceSize, int indexCount, int scrollCount) {
        ······
        normalPaint = new Paint();
        focusPaint = new Paint();
        normalPaint.setAntiAlias(true);
        focusPaint.setAntiAlias(true);
        normalPaint.setColor(mNormalColor);
        focusPaint.setColor(mFocusColor);
        if (mMode == GuideView.MODE_ALPHA) {
            focusPaintNormal = new Paint();
            focusPaintNormal.setAntiAlias(true);
            focusPaintNormal.setColor(mFocusColor);
            focusPaintNormal.setAlpha(0);
        }
        initPaintTools();
    }

    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        switch (mMode) {
            case GuideView.MODE_CHANGE:
                ······    
                break;
            case GuideView.MODE_ALPHA:
                ······ 
                break;
            case GuideView.MODE_SLIDE:
                ······ 
                break;
            case GuideView.MODE_SCROLL:
                ······ 
                break;
        }
    }

    public void onPageSelected(int position) {
    }

    public void onPageScrollStateChanged(int state) {
        ······ 
    }

3.Circle、Triangle、Square、Diamond类
对应形状的绘制实现、刷新等。

四、版本更新

Version 1.2

1、新增“滚动”模式
2、优化响应模式

Version 1.1

1、优化重绘机制
2、自适应父布局

Version 1.0

Release notes 初始化提交

四、其他

github
望诸君多多指教!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容