博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 自定义 View 之 实现一个多功能的 IndicatorView
阅读量:6411 次
发布时间:2019-06-23

本文共 6226 字,大约阅读时间需要 20 分钟。

Indicator (指示器) 可能大家都见的比较多了,在一个APP中,有很多场景都会用到Indicator,比如第一次安装APP 时的引导页,首页上面的广告Banner ,又或者是Tab下面的Indicator。Indicator 一般配合ViewPager 使用,它能很直观的反应出ViewPager 中一共有多少页,当前选中的是哪一页,用户能够很容易的看出是否还可以滑动,用户体验较好。那么本篇文章就讲一下如何通过自定义View来实现一个漂亮简洁的IndicatorView。

Indicator的展示形式

我们使用Indicator时,常见的有三种形式,第一种是根据ViewPager 的总页数展示一排小圆点,选中和未选中分别标为不同的颜色。这也是普遍的使用Indicator的效果,效果如下:

image.png

第二种形式是根据ViewPager 的总页数展示一排圆点,并且用数字标出其顺序(1,2,3,4 ...),大概效果如下:

image.png

第三种形式和第二种形式差不多,同样根据ViewPager总页数展示一片圆点,但是用字母标出顺序(A,B,C,D ....), 比如 :魅族手机屏幕的切换的Indicator。效果如下:

image.png

本篇文章就通过自定义View来实现这三种IndicatorView。

通过自定义View 实现多功能的CircleIndicatorView

首先整理一下思路,CircleIndicatorView ,它是由一组圆 组成的,只不过圆有多种状态,选中、未选中、显示字母、显示数字等等。看着有这么多中状态,感觉挺复杂,但是其实不复杂,只是用不同的变量来控制不同的状态即可。其他的先不考虑,我们只要先把这一排圆画出来,剩下的就比较容易了。要确定一个圆的,需要知道圆的半径和圆心,半径是我们可以配置的,那么,其实核心就是计算这一排的圆点的圆心位置。圆心 y 的位置是固定的(View 高的一般),因此我们只需要计算每个圆的圆心x的位置,看下图,其实很容易就能找到规律,规律如下: 第一个圆的x 就等于圆的半径,从第二个圆开始,当前圆的圆心x 坐标为 上一个圆的x 坐标 + (radius * 2 + mSpace)。 其中mSpace 是圆之间的间距。

圆心x坐标计算公式.png

有了上面的规律,我们只需要一个循环就能找出所有圆的圆心位置。代码如下:

/**     * 测量每个圆点的位置     */    private void measureIndicator(){        mIndicators.clear();        float cx = 0;        for(int i=0;i

我们用Indicator类记录了每个圆的圆心位置,并且保存在一个列表里面,现在有了所有圆的数据,我们就可以绘制 了。

@Override    protected void onDraw(Canvas canvas) {        for(int i=0;i
= 0 && i

绘制的代码很简单,无非就是循环我们保存的列表,拿出每一个Indicator,然后绘制圆就行了,除此之外就是一些状态的判断,比如,是否绘制数字、字母和选中状态等等 。

到此,我们的CircleIndicatorView 的绘制工作算是完成了,并且也能够显示在界面上了,但是它现在还是一个单独的View。我们前面说过,IndicatorView 一般是配合ViewPager使用的,它是随着Viewpager的切换而改变的,因此我们需要将IndicatorView 与ViewPager 进行关联。

要让CircleIndicatorView 与ViewPager 关联,首先需要 CircleIndicatorView 实现 ViewPager.OnPageChangeListener 接口。然后在onPageSelected方法中记录当前页的位置。代码如下:

@Override    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {    }    @Override    public void onPageSelected(int position) {        mSelectPosition = position;        invalidate();    }    @Override    public void onPageScrollStateChanged(int state) {    }复制代码

第二步,向外提供一个API ,设置CircleIndicatorView 与 ViewPager 关联。

/**     *  与ViewPager 关联     * @param viewPager     */    public void setUpWithViewPager(ViewPager viewPager){        releaseViewPager();        if(viewPager == null){            return;        }        mViewPager = viewPager;        mViewPager.addOnPageChangeListener(this);        int count = mViewPager.getAdapter().getCount();        setCount(count);    }复制代码

通过如上两步,就建立了CircleIndicatorView 与ViewPager的关联,只需要调用方法setUpWithViewPager 就OK。

到此就完了吗?当然还没有完,其实还有一个小细节,那就是IndicatorView 因该是可以点击的,点击Indicator小圆点就能切换ViewPager 到对应的页面(如 Iphone 和 魅族手机的 屏幕切换,点击indicator小圆点就可以切换 ,以前没有注意的现在可以去试一下 ),那么我们也来实现这样一个功能,其实很简单,重写onTouchEvent方法 ,监听ACTION_DOWN 事件,然后获取点击屏幕的坐标,与所绘制的圆位置比较,如果点击区域在圆的范围内,就点击了该Indicator。点击之后,切换Viewpager到对应页面。代码如下:

@Override    public boolean onTouchEvent(MotionEvent event) {        float xPoint = 0;        float yPoint = 0;        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                xPoint = event.getX();                yPoint = event.getY();                handleActionDown(xPoint,yPoint);                break;        }        return super.onTouchEvent(event);    }    private void handleActionDown(float xDis,float yDis){        for(int i=0;i
=(indicator.cx - (mRadius + mStrokeWidth)) && yDis >= (yDis - (indicator.cy+mStrokeWidth)) && yDis <(indicator.cy+mRadius+mStrokeWidth)){ // 找到了点击的Indicator // 切换ViewPager mViewPager.setCurrentItem(i,false); // 回调 if(mOnIndicatorClickListener!=null){ mOnIndicatorClickListener.onSelected(i); } break; } } }复制代码

到此,我们自定义IndicatorView 的工作就差不多完成了,但是现在的IndicatorView 还不是很灵活,我们要让它的可配置性更强,就应该提供更多的API 来让IndicatorView 使用更加灵活方便,因此,最后一步,加上一些自定义属性来提高它的灵活性。自定义了如下一些属性:

属性名 属性意义 取值
indicatorRadius 设置指示器圆点的半径 单位为 dp 的值
indicatorBorderWidth 设置指示器的border 单位为 dp 的值
indicatorSpace 设置指示器之间的距离 单位为 dp 的值
indicatorTextColor 设置指示器中间的文字颜色 颜色值,如:#FFFFFF
indicatorColor 设置指示器圆点的颜色 颜色值
indicatorSelectColor 设置指示器选中的颜色 颜色值
fill_mode 设置指示器的模式 枚举值:有三种,分别是letter,number和none

自定义属性文件如下:

复制代码

通过上面这些属性,我们就可以很好的定制IndicaotorView 了,比如,自定义圆的大小,颜色,border,文字的颜色,选中的颜色和展示的模式等等。

最终的效果如下:

CircleIndicator最终效果.gif

CircleIndicatorView 使用方法

上面讲了自定义IndicatorView 的思路、过程 和一些关键代码,为了使用方便,已经将CircleIndicatorView封装成了一个库,以下介绍一下CircleIndicatorView API的使用。Github 地址:

Dependency

1, 最外层build.gradle添加如下代码:

allprojects {       repositories {    ...    maven { url 'https://jitpack.io' }   }}复制代码

2, app 层buid.gradle dependencies 中 添加如下代码:

compile 'com.github.pinguo-zhouwei:CircleIndicatorView:v1.0.0'复制代码

使用方法如下:

1, xml 添加CircleIndicatorView,配置相关属性

复制代码

2, 在代码中与ViewPager 关联

// 初始化ViewPager 相关          mViewPager = (ViewPager) findViewById(R.id.viewpager);          mPagerAdapter = new ViewPagerAdapter();          mViewPager.setAdapter(mPagerAdapter);          mIndicatorView = (CircleIndicatorView) findViewById(R.id.indicator_view);          // 关联ViewPager           mIndicatorView.setUpWithViewPager(mViewPager);复制代码

上面所有列举的属性,出了在xml 中配置外,也可以在代码中设置,如下:

// 在代码中设置相关属性          CircleIndicatorView indicatorView = (CircleIndicatorView) findViewById(R.id.indicator_view3);          // 设置半径          indicatorView.setRadius(DisplayUtils.dpToPx(15));          // 设置Border          indicatorView.setBorderWidth(DisplayUtils.dpToPx(2));          // 设置文字颜色          indicatorView.setTextColor(Color.WHITE);          // 设置选中颜色          indicatorView.setSelectColor(Color.parseColor("#FEBB50"));          //          indicatorView.setDotNormalColor(Color.parseColor("#E38A7C"));          // 设置指示器间距          indicatorView.setSpace(DisplayUtils.dpToPx(10));          // 设置模式          indicatorView.setFillMode(CircleIndicatorView.FillMode.LETTER);          // 最重要的一步:关联ViewPager          indicatorView.setUpWithViewPager(mViewPager);复制代码

最后

以上就是通过自定义View的方式实现一个多功能的IndicatorView的全部内容,内容很简单,通过自定义的View方式实现很方便,免得每次还得找设计师要切图啊(能自己动手的,就不找设计师要了。?)。如有问题欢迎交流,最后,如果你觉得不错的话,欢迎github 赏个start啊!!轮子传送门

转载地址:http://kkkra.baihongyu.com/

你可能感兴趣的文章
腾讯Hermes设计概要——数据分析用的是列存储,词典文件前缀压缩,倒排文件递增id、变长压缩、依然是跳表-本质是lucene啊...
查看>>
小程序模板嵌套以及相关遍历数据绑定
查看>>
Systemd入门教程:命令篇(转)
查看>>
java随机范围内的日期
查看>>
linux包之diff
查看>>
spring事务学习(转账案例)(二)
查看>>
[官方教程] [ES4封装教程]1.使用 VMware Player 创建适合封装的虚拟机
查看>>
http协议与http代理
查看>>
【iOS开发-91】GCD的同步异步串行并行、NSOperation和NSOperationQueue一级用dispatch_once实现单例...
查看>>
Redis+Spring缓存实例
查看>>
Storm集群安装详解
查看>>
centos7.x搭建svn server
查看>>
原码编译安装openssh6.7p1
查看>>
项目实战:自定义监控项--监控CPU信息
查看>>
easyui-datetimebox设置默认时分秒00:00:00
查看>>
蚂蚁分类信息系统5.8多城市UTF8开源优化版
查看>>
在django1.2+python2.7环境中使用send_mail发送邮件
查看>>
“Metro”,移动设备视觉语言的新新人类
查看>>
PHP源代码下载(本代码供初学者使用)
查看>>
Disruptor-NET和内存栅栏
查看>>