登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

查看: 437|回复: 0

Android实现一个可爱的ViewPager指示器

[复制链接]

345

主题

349

帖子

7657

安币

手工艺人

发表于 2019-1-25 09:55:01 | 显示全部楼层 |阅读模式
如果对本篇文章感兴趣,请前往,原文地址:http://www.apkbus.com/blog-822719-79442.html

在很久以前,我写了一个android广告栏控件,其实当时只是学习之用,自己也不是很懂,一边写代码一边查资料及其他开源控件,勉勉强强的算是完成了,现在github上也有了几百个star,时至今日,我也一直在用,中间也没太多的精力把这个库完善,因为本来就是主打简单实用,所以功能不多,拓展性也一般,根据网友的要求,中间将图片加载模块提取出来了,但指示器封装到了BannerLayout内部了,前段时间我们的设计出了一款圆角矩形的指示器,而且带有阴影效果,之前的方法就不行了,趁着有点空闲的时间,又单独写了个指示器控件,如下:![Picture](//upload-images.jianshu.io/upload_images/697635-445df60f1a2edefc.gif)github传送门:[CuteIndicator](https://github.com/dongjunkun/CuteIndicator)### 实现思路通过 重新onDraw方法绘制指示器,好多table指示器都是通过这种方法实现的,可以尝试下,而且paint包含有setShadowLayer方法可绘制阴影。### Step by Step#### 1、先新建一个自定义View继承于LinearLayout,重写构造函数,重写OnDraw方法,如下:```class CuteIndicator : LinearLayout {    constructor(context: Context) : super(context) {        init(null, 0)    }    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {        init(attrs, 0)    }    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {        init(attrs, defStyle)    }    private fun init(attrs: AttributeSet?, defStyle: Int) {        val a = context.obtainStyledAttributes(                attrs, R.styleable.CuteIndicator, defStyle, 0)       //自定义属性赋值          a.recycle()    }    override fun onDraw(canvas: Canvas) {        super.onDraw(canvas)    }```也可以利用android Studio创建自定义View模板。#### 2、重写onDraw随便画点东西```  override fun onDraw(canvas: Canvas) {        super.onDraw(canvas)          rectf.left = getLeft()          rectf.top = getTop()          rectf.right = getRight()          rectf.bottom = getBottom()         canvas.drawRect(rectf,paint)    }```这个地方有点小坑,试了一会儿,onDraw方法都没有触发,继承View会默认触发,但继承LinearLayout不会,依靠万能的搜索引擎,发现了几行有用的代码```fun init(){        ...        //允许Draw        setWillNotDraw(false)        ...}//触发onDraw方法,至于两个方法区别,自行查阅invalidate()postInvalidate()```终于在控制台检测到了onDraw方法被执行,但画面依旧是一片空白,什么也没有画上去,检查了一下,所有方法都执行了,每个值都能打印出来,问题出在位置不对,getLeft(),getRight(),getTop(),getButtom()获取的是控件在界面的绝对位置,而每个控件都有单独的坐标体系,左上角(0,0)开始,只需做如下修改```  rectf.left = 0  rectf.top = 0  rectf.right = getWidth()  rectf.bottom = geHeight()```#### 3、开始绘制一个不含动画效果的指示器(先易后难)![Picture](//upload-images.jianshu.io/upload_images/697635-55bf2e74ab5e1e42.gif)先捋一下需要确定哪些东西,在最开始我已经展示了效果图,选中的是一个圆角矩形,未选中的是一个圆形,selectedWidth(选中的指示器宽度),dia(圆形的直径),space(任意两个指示器直径的间距),假设默认选中第一个,没有动画的指示器仅仅在广告栏滑动过去后才进行切换```override fun onPageSelected(position: Int) {                super.onPageSelected(position)                                firstVisiblePosition = position                invalidate()                 }```只需要在onPageSelected方法中监听页面是否已经切换,调用 invalidate()  绘制就可以了#### 4、绘制阴影之前在说实现思路上没有采用XML或者GradientDrawable方式,其原因就是无法绘制阴影,因为android没有提供相应的api,关键代码,两行代码缺一不可,都加上才有效果```setLayerType(View.LAYER_TYPE_SOFTWARE, null)setShadowLayer(shadowRadius, shadowRadius / 2, shadowRadius / 2, shadowColor.toInt())```效果预览,为了看效果,弄个夸张一点的黑色,具体阴影颜色可通过自定义属性进行设置![Picture](//upload-images.jianshu.io/upload_images/697635-1d0bcbaa9a783005.gif)#### 5、开始绘制根据页面滑动,指示器便会相应反应的指示器,跟手动画,也是最终效果,至于onDraw里面的算法,我不准备多讲,代码在github上ViewPager的onPagerChangeListener有三个方法,上面已经重写了一个,如果想要指示器跟随着页面进行变化,便要用到这个方法进行监听```override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {                super.onPageScrolled(position, positionOffset, positionOffsetPixels)                firstVisiblePosition = position                lastPositionOffset = positionOffset                invalidate()            }```- position是ViewPager第一个可见的页面位置- positionOffset滑动的距离比例[0,1]- positionOffsetPixels实际滑动的距离最开始的思路是想要监听页面是向左还是向右滑动,然后再去计算,然后发现完全没必要。http://www.apkbus.com/thread-605317-1-1.html代码量很少,重在理解。  继续阅读全文



想在安卓巴士找到更多优质博文,可移步博客区

如果对本篇文章感兴趣,请前往,
原文地址:
http://www.apkbus.com/blog-822719-79442.html
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表