专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
stormzhang  ·  双十一晚会不香了? ·  昨天  
鸿洋  ·  鸿蒙中是如何实现UI自动刷新的? ·  5 天前  
鸿洋  ·  Android从上帝视角来看PackageM ... ·  6 天前  
stormzhang  ·  不让人们存钱了? ·  1 周前  
51好读  ›  专栏  ›  郭霖

FreeRadioGroup一一淡出、自由拖动、自动贴边

郭霖  · 公众号  · android  · 2017-01-03 08:00

正文

新年快乐

让风吹走你的忧愁;让雨洗去你的烦恼;让阳光给你带来温暖;让亲情给你带来温馨;让爱情给你带来激情;让朋友给你带来无限的快乐和祝福!亲爱的朋友们,2017新年快乐!

作者简介

本篇是2017年第一次推送,来自 Sbingo 的投稿,实现了一个类似苹果辅助按钮的组件,大家赶快来看一看吧。

Sbingo 的博客地址:

http://blog.csdn.net/recordgrowth

Demo演示

简单描述

这个可自由拖动的 RadioGroup 在松手后能自动贴合父布局的左侧或右侧并淡出,同时它对 setOnCheckedChangeListener 没有造成影响。

虽然它是个 RadioGroup,但所用的思路和方法可以轻松地将任意的View或ViewGroup实现类似的功能。(有多简单?我会告诉你只要将继承的父类改一下就好了么……)

由来

项目中需要用demo中所示的三个选择来切换页面,我选择了用 RadioGroup 来做这个,本来也很顺利,轻松就搞定这个了。但作为追求用户体验的程序员,对这一坨黑黑的区域实在看不下去了,决定给它加个淡出功能。

本来弄个 onTouchListener 就可以了,可是这和 setOnCheckedChangeListener 有冲突,触摸事件被子view消耗了,就不会进入 onTouch 方法中了,如果把事件拦截了,OnCheckedChange 方法又会没用了。

所以我想了一下,可以在 RadioGroup 的分发或拦截方法中实现淡出,但不消耗事件,继续向下分发,也就不会对 OnCheckedChange 方法造成影响。后来自定义了 RadioGroup 就一发不可收拾,决定干脆将它的功能做得更完善,否则我会睡不着的!于是,一个功能还算可以的 FreeRadioGroup 就诞生了~

技术分析

淡出

我使用了定时器 CountDownTimer,在初始化时开始倒计时:


在倒计时结束时改变透明度,实现淡出效果:


在分发事件中,手指按下时取消倒计时,同时恢复到不透明状态:

case MotionEvent.ACTION_DOWN:
    setAlpha(1f);
    countDownTimer.cancel();
   break;

手指松开后,重新开始倒计时:

case MotionEvent.ACTION_UP:
    countDownTimer.start();
   break;

这样,就实现了触摸时不透明,松手后到达预定时间就淡出到预定透明度的效果。

自由拖动

我通过控制 leftMargin topMargin 来实现拖动功能,按照以下步骤实现:

在手指按下时,记录当前触摸点的绝对坐标和当前的 margin


手指移动过程中,计算出触摸点移动的距离,将算出的移动距离加上之前记录的 margin 值作为当前的 margin 并赋值,然后更新当前触摸点的绝对坐标,就可以实现跟随手指移动了。


但是光这样还不够,因为没有控制好边界,会出现你不想看到的画面,哈哈。

下面我们来控制移动边界,使其在合理的范围内移动。

既然我是通过 leftMargin topMargin 来实现拖动功能,就要分别算出这两个值的最小和最大值,使它们一直处于最小和最大值之间,边界问题自然就解决了。

先来看我画的一张示意图:

如上图所示:我们要将移动范围控制在白色区域内,两个红色箭头所示的距离就是我们的控制手段。

很明显,minLeftMargin 就是左侧的蓝色距离,minTopMargin 就是上部的蓝色距离,而最大值的计算请看以下代码,相信聪明的你一看就懂了。这些计算我放在 onSizeChanged 方法中(为什么?你懂的):


这样就获得了 minLeftMargin、maxLeftMargin、minTopMargin、maxTopMargin 这4个主要数值以及其他辅助数值。

接下来就要在移动的过程中检查并控制在边界之内:


这样不管怎么拖动,始终在合理的边界中,拖起来就更爽了!

松手后贴边

我只做了左右贴边,简单地判断了下松手时距离父布局左右距离的大小来决定贴左侧还是右侧。

因为我们已经有了 minLeftMargin 和 maxLeftMargin,所以这个就简单了,只需要将 minLeftMargin 或 maxLeftMargin 作为松手后的 leftMargin 就可以了。

但是这样直接赋值效果会很突兀,突然出现在侧边了。于是,我们给它加个属性动画,慢慢地回到侧边。

首先写一个包装类:


这个包装类会告诉系统对 leftMargin 这个属性该干什么,在里面我们对 leftMargin 赋予新值并重绘,随着时间的推移,leftMargin 不断改变,从而实现动画效果。

接着在手指放开后,判断左右距离,利用这个包装类,开始500ms的动画:


你会发现、你会讶异,它就这样回到了侧边~~~

深藏功与名

要知道,我们这些功能是写在分发事件中的,可不能因此导致子view某些功能失效。因此最后别忘了加这么一句:

return super.dispatchTouchEvent(ev);

就这样,深藏功与名,假装自己什么都没干,你的子View们啥也母鸡,哈哈哈。

库使用方法


compile 'com.github.Sbingo:FreeRadioGroup:v1.0.0'


https://github.com/Sbingo/FreeRadioGroup

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号: