Android之实现妙趣横生的粘连布局

1概述

在手机QQ中,有一个功能叫“一键下班”,无论界面有多少信息,只要你不想看,就可以手指一滑,将他们全部消灭。据说这个功能专为红点恐惧症、信息阅读强迫症以及处女座暖心打造。这个功能已经上线许久,除了设计本身比较贴心外,其呈现效果也十分惊艳:

这个功能深受广大用户喜爱,那么这样一个场景到底是怎样的实现的呢?面对各位开发哥哥的疑问,小编决定玩个大的,既然要写,不如就写一个拓展性强大一点的、不仅仅只适用于“一键下班”场景的吧,干脆叫它粘连布局 —— AdherentLayout。

2AdherentLayout

AdherentLayout是一个适用于粘连场景的的开源组件,它有以下特性:

1、除了可实现类似手Q“一键下班”场景,还可以实现其他你能想到的其他场景。

2、支持设置粘连长度、粘连头部大小、粘连颜色、是否可以扯断的设置。

3、支持用户自定义粘连尾部的视图定制。

4、支持扯断时候的监听事件。

3使用方法

<AdherentLayout>

<!-- 在这里可以添加用户的视图(可选) -->  
< />

</AdherentLayout>

4接口说明

setColor(int color)

设置粘连颜色

setDismissedEnable(boolean isDismissed)

设置是否可以扯断

setMaxAdherentLength(int maxAdherentLength)

设置粘连的最大长度

setMinHeaderCircleRadius(int minHeaderCircleRadius)

设置粘连头部圆的最小半径

setOnAdherentListener(OnAdherentListener onAdherentListener)

设置粘连事件的监听器

5核心技术

要实现粘连效果,最重要的是掌握贝塞尔曲线的绘制。

6贝塞尔曲线

通俗的讲,贝塞尔曲线就是用来精确画出曲线的,通过若干个控制点来控制曲线的形状与绘制。因为Android本身自带支持二阶、三阶的贝塞尔曲线绘制的API,所以下面就只引出二阶、三阶的动态图好了,具体的知识点可移步贝塞尔曲线初探。

二阶:

三阶:

从上图可知,

二阶是只有一个控制点,对应quadTo(float x1, float y1, float x2, float y2),其中(x1,y1)是控制点,(x2,y2)是结束点。

三阶有两个控制点,对应cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) ,其中(x1,y1)是第一控制点,(x2,y2)是第二控制点,(x3,y3)是结束点。

7具体实现

借用ISUX的一张图,该粘连布局的具体流程分以下两种情况:

1、未超出粘连范围:边拖拽边绘制粘连头部圆、粘连尾部圆和粘连体。其中头部圆和尾部圆都是用drawCircle进行绘制,粘连体通过p1、p2、p3、p4、控制点采用quadTo绘制两条二阶贝塞尔曲线并分别连接p1p3、p2p4闭合起来,取两圆心距离的中点为控制点,通过拖拽过程中两圆心的距离之比来控制头部圆的放大缩小即可。松开手势,开启回弹动画。

2、超出粘连范围:只绘制粘连尾部圆即可。松开手势,绘制结束。

其中,绘制粘连体的核心代码如下:

private void drawBezier(Canvas canvas) {


/* 求三角函数 */
float atan = (float) Math.atan((mFooterCircle.y - mHeaderCircle.y) / (mFooterCircle.x - mHeaderCircle.x));
float sin = (float) Math.sin(atan);
float cos = (float) Math.cos(atan);


/* 四个点 */
float headerX1 = mHeaderCircle.x - mCurrentRadius * sin;
float headerY1 = mHeaderCircle.y + mCurrentRadius * cos;


float headerX2 = mHeaderCircle.x + mCurrentRadius * sin;
float headerY2 = mHeaderCircle.y - mCurrentRadius * cos;


float footerX1 = mFooterCircle.x - mFooterCircle.radius * sin;
float footerY1 = mFooterCircle.y + mFooterCircle.radius * cos;


float footerX2 = mFooterCircle.x + mFooterCircle.radius * sin;
float footerY2 = mFooterCircle.y - mFooterCircle.radius * cos;


/* 控制点 */
float anchorX = ( mHeaderCircle.x + mFooterCircle.x ) / 2;
float anchorY = ( mHeaderCircle.y + mFooterCircle.y ) / 2;


/* 画贝塞尔曲线 */
mPath.reset();
mPath.moveTo(headerX1, headerY1);
mPath.quadTo(anchorX, anchorY, footerX1, footerY1);
mPath.lineTo(footerX2, footerY2);
mPath.quadTo(anchorX, anchorY, headerX2, headerY2);
mPath.lineTo(headerX1, headerY1);
canvas.drawPath(mPath, mPaint);
}

8运行示例

9结语

听说这个功能的效果实现,经过了开发与产品多次脑暴与打磨。之所以受用户喜爱,除了实用外,更重要的是实现效果让用户觉得更有趣,更灵动,也更软性。而且这个效果其实可以适用于多种场景。

腾讯Bugly 最专业的质量跟踪平台

精神哥、小萝莉,为您定期分享应用崩溃解决方案

本文分享自微信公众号 - 腾讯Bugly(weixinBugly)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2015-09-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员互动联盟

安卓是如何改变了嵌入式格局

大家一提到嵌入式就是linux、讲到android就认为是java,以为android已经不是linux了,各种应用都是android API开发的,而andr...

45440
来自专栏程序员互动联盟

【答疑释惑第六讲】编程找工作对大学要求高吗?

疑惑一 编程找工作对大学要求高吗? 很多人一边学着编程一边心里有个疑问就是这行出来找工作对大学要求高吗?这个问题平心而论要看情况的。一般的BAT这样的大公司对于...

34750
来自专栏程序员互动联盟

【答疑释惑】linux学习线路图

随着android的大热,基于linux的开发也更热了。linux的开发包括driver的开发以及应用程序的开发。 由于我们习惯了windows,在开始使用l...

35040
来自专栏程序员互动联盟

【入门指导第十二讲】安卓新的开发工具

存在问题: 随着新的安卓开发工具android studio的推出,gradle这个词出现在了我们初学者的面前。它是什么东西呢?它有和android studi...

42690
来自专栏程序员互动联盟

【专业技术】谷歌浏览器命令行探索之旅

存在问题: 浏览器开发经常需要调试、测试某个模块,比如看看跨域问题,3D问题等等,清楚知道那些常用的开关能给我们带来极大便利,在不方便单步调试的时候这是唯一好用...

41060
来自专栏程序员互动联盟

【编程基础】Android中如何获取资源的尺寸?

在Android中为了实现不同屏幕的适配,经常会用到在不同dimen.xml文件中对于同一dimen ID定义不同的大小,然后在代码中通过getDimensio...

36870
来自专栏程序员互动联盟

怪不得java工资高,原来是有这么多岗位

目前,虽然JAVA人才的薪水很高,但是对该类人才需求旺盛的IT公司却很难招聘到合格的JAVA人员。其中,最根本的原因就是许多计算机专业的毕业生在读期间没有掌握实...

41090
来自专栏程序员互动联盟

【专业技术第四讲】如何检测浏览器的快慢?

现在做浏览器的大概有下面几个方向吧 1. 从事浏览器外壳的工作,开发基于浏览器的各种应用和扩展; 2. 做浏览器内核优化的,大概又分为几个部分: a. 渲染模块...

363120
来自专栏程序员互动联盟

【编程基础第八讲】如何选择Android模拟器?

存在问题: android开发如何选择一款好的模拟器? 解决方案: ? 网友们经常会问一些关于Android模拟器的问题,我今天就给大家总结一下。 1、Andr...

38670
来自专栏程序员互动联盟

【专业技术】Android 启动性能优化 - uboot篇

时间测量 在mx51平台的uboot里,使用get_timer可以获得比较精确的计时,get_timer的使用贯穿了uboot性能调整的整个过程。 性能优化方法...

48880

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励