Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发鼻涕下拉粘连效果
前言
接着上一期 Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件 的博客开始,同样,在开始前我们先来看一下目标效果:
下面上一下本章需要实现的效果图:
大家看到这个效果肯定不会觉得陌生,QQ已经把粘滞效果做的满大街都是,相信不少读者或多或少对于贝塞尔曲线有所了解,不了解的朋友们也没有关系,在这里我会带领读者领略一下贝塞尔的魅力!
一、关于贝塞尔曲线
我们知道,任何一条线段是由起始点和终止点的连线组成,两点组成一条直线,这就是最简单的一阶公式(就是线段):
一阶贝塞尔曲线表达公式(图略):
B(t) = P0 + ( P1 - P0 ) t = ( 1 - t ) P0 + t P1 , t∈[0,1]
很显然,一阶的贝塞尔只是用于一条线段,其中t的变化率代表着线性插值大小.所以我们的效果用于一阶贝塞尔曲线公式肯定不行,下面我们来着重介绍一下二阶(次)贝塞尔曲线变化率和公式:
(图片来自于网络)
公式:
B(t) = ( 1 - t )² P0 + 2 t ( 1 - t ) P1 + t² P2 , t∈[0,1]
其实公式对于我们的开发者来说并没有太大的意义,因为主要的算法我们的API都已经包含,不过我们需要了解的是,我们的辅助点的查找.首先,我们需要了解曲线是如何画出来的?从图中我们可以看出我们的辅助点是p1点,由p0和p1组成的线段加上p1和p2组成的线段一共是有两条线段,我们需要一个变化率t,t从p0走到p1和从p1走到p2的时间是一样的,这样我们连接两点,就产生了第三条直线(图中绿色的线),这条直线其实就是我们的贝塞尔曲线的切线,只要有了这条直线,我们就可以确定我们的贝塞尔曲线轨迹(这一点至关重要).
当然,有一阶二阶,肯定也会有三阶、四阶等等.因为辅助点的增加,曲线也会发生各种变化,在这里,博主就不介绍了,想了解更深入的读者,可以在很多关于贝塞尔的博客中去了解.
介绍完了贝塞尔曲线,接下来我们就要开始着手打造QQ的粘滞效果了.在开始编写代码前我们先分析一下,我们要实现这个效果所需要的准备工作:
- 自定义View先绘制两个同样大小并重叠的圆形
- 按照小圆的大小我们设置圆形上刷新图标
- 重写触摸事件,绘制我们的贝塞尔曲线
- 动画收回
二、自定义View绘制圆形
/*** 圆的画笔*/private Paint circlePaint;/*** 画笔的路径*/private Path circlePath;/*** 可拖动的最远距离*/private int maxHeight;/*** 刷新图标*/private Bitmap bt;private float topCircleRadius;//默认上面圆形半径private float topCircleX;//默认上面圆形xprivate float topCircleY;//默认上面圆形yprivate float bottomCircleRadius;//默认上面圆形半径private float bottomCircleX;//默认下面圆形xprivate float bottomCircleY;//默认下面圆形yprivate float defaultRadius;//默认上面圆形半径float offset=1.0f;float lastY;OnAnimResetListener listener;ObjectAnimator anim;
public YPXBezierView(Context context) {this(context, null);}public YPXBezierView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public YPXBezierView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}protected void init() {maxHeight=dp(60);topCircleX=ScreenUtils.getScreenWidth(getContext())/2;topCircleY=dp(100);topCircleRadius=dp(15);bottomCircleX=topCircleX;bottomCircleY=topCircleY;bottomCircleRadius=topCircleRadius;defaultRadius=topCircleRadius;circlePath = new Path();circlePaint = new Paint();circlePaint.setAntiAlias(true);circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);circlePaint.setStrokeWidth(1);circlePaint.setColor(Color.parseColor("#999999"));}
@Overrideprotected void onDraw(Canvas canvas) {drawPath();float left=topCircleX-topCircleRadius;float top=topCircleY-topCircleRadius;canvas.drawPath(circlePath, circlePaint);canvas.drawCircle(bottomCircleX, bottomCircleY, bottomCircleRadius, circlePaint);canvas.drawCircle(topCircleX, topCircleY, topCircleRadius, circlePaint);int btWidth=(int) topCircleRadius* 2-dp(6);if ((btWidth) > 0) {bt = BitmapFactory.decodeResource(getResources(), R.mipmap.refresh);bt = Bitmap.createScaledBitmap(bt,btWidth, btWidth, true);canvas.drawBitmap(bt, left+dp(3), top+dp(2) , null);bt.recycle();}super.onDraw(canvas);}
这个方法了,画圆形的代码不用多说,直接drawCircle就好,关于刷新图标,我们需要说一下,因为我们的刷新图标是需要跟随大圆的大小变化而变化的,所以它自身的大小一定是可变的,我查阅了关于修改bitmap大小的方法,发现只有在创建的时候使用createScaledBitmap方法,该方法支持bitmap的缩放,但是美中不足的是,它的效果是叠加的,如果把bitmap只创建一次并且不去释放,那么每次刷新的时候会发现我们的刷新图标越来越模糊,目前博主没有什么好的解决方案,只能在绘制的时候重新生成bitmap,如果有了解更优化的方案的话,欢迎大神联系交流~我们的边距是3dp,所以我们的位置需要减去6dp,这样看起来效果更好一点!
三、绘制贝塞尔曲线
图中有六个重要的点,p1、p2、p3、p4、anchor1、anchor2,因为我们的粘滞小球尽量需要平滑一点,所以博主选择了最简单的四个交叉点(p1~p4),这四个点不涉及到三角函数的处理,所以坐标很容易的就可以得到:
private void drawPath() {float p1X = topCircleX - topCircleRadius ;float p1Y = topCircleY ;float p2X = topCircleX + topCircleRadius;float p2Y = topCircleY ;float p3X = bottomCircleX - bottomCircleRadius ;float p3Y = bottomCircleY ;float p4X = bottomCircleX + bottomCircleRadius ;float p4Y = bottomCircleY ;float anchorX = (p1X+ p4X) / 2-topCircleRadius*offset;float anchorY = (p1Y + p4Y) / 2;float anchorX2 = (p2X +p3X) / 2+topCircleRadius*offset;float anchorY2 = (p2Y + p3Y) / 2;/* 画粘连体 */circlePath.reset();circlePath.moveTo(p1X, p1Y);circlePath.quadTo(anchorX, anchorY, p3X, p3Y);circlePath.lineTo(p4X, p4Y);circlePath.quadTo(anchorX2, anchorY2, p2X, p2Y);circlePath.lineTo(p1X, p1Y);}
三、触摸事件监听以及收回
private void drawPath() {float p1X = topCircleX - topCircleRadius ;float p1Y = topCircleY ;float p2X = topCircleX + topCircleRadius;float p2Y = topCircleY ;float p3X = bottomCircleX - bottomCircleRadius ;float p3Y = bottomCircleY ;float p4X = bottomCircleX + bottomCircleRadius ;float p4Y = bottomCircleY ;float anchorX = (p1X+ p4X) / 2-topCircleRadius*offset;float anchorY = (p1Y + p4Y) / 2;float anchorX2 = (p2X +p3X) / 2+topCircleRadius*offset;float anchorY2 = (p2Y + p3Y) / 2;/* 画粘连体 */circlePath.reset();circlePath.moveTo(p1X, p1Y);circlePath.quadTo(anchorX, anchorY, p3X, p3Y);circlePath.lineTo(p4X, p4Y);circlePath.quadTo(anchorX2, anchorY2, p2X, p2Y);circlePath.lineTo(p1X, p1Y);}
public void animToReset(boolean lock){if(!lock) {Log.e("onAnimationEnd", "动画开始");anim= ObjectAnimator.ofFloat(offset, "ypx", 0.0F, 1.0F).setDuration(200);//使用反弹算法插值器,貌似没有什么太大的效果 - -!anim.setInterpolator(new BounceInterpolator());anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float cVal = (Float) animation.getAnimatedValue();offset = cVal;bottomCircleX=bottomCircleX+(topCircleX-bottomCircleX)*offset;bottomCircleY=bottomCircleY+(topCircleY-bottomCircleY)*offset;bottomCircleRadius=bottomCircleRadius+(topCircleRadius-bottomCircleRadius)*offset;topCircleRadius=topCircleRadius+(defaultRadius-topCircleRadius)*offset;postInvalidate();}});anim.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animator) {}@Overridepublic void onAnimationEnd(Animator animator) {Log.e("onAnimationEnd", "动画结束");if (listener != null) {listener.onReset();}}@Overridepublic void onAnimationCancel(Animator animator) {}@Overridepublic void onAnimationRepeat(Animator animator) {}});anim.start();}}
四、使用和总结
感谢大家的支持,谢谢!
作者:yangpeixing
QQ:313930500
下载地址:http://download.csdn.net/detail/qq_16674697/9741375
转载请注明出处~谢谢~
转载于:https://www.cnblogs.com/teamblog/p/8032316.html
Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发鼻涕下拉粘连效果相关推荐
- Android仿苹果版QQ下拉刷新实现(三)
前言 第三篇下拉刷新的博客来的稍微有点晚,因为前两篇的博客访问量一直不是很高,所以博主花了点时间修改了整体的Demo效果,处理了很多极端下拉情况下的显示问题,给大家呈现一个完美的下拉刷新控件.因为本文 ...
- Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件
前言: 因为公司人员变动原因,导致了博主四个月没有动安卓,一直在做IOS开发,如今接近年前,终于可以花一定的时间放在安卓上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下 ...
- android 今日头条加载动画,Android 仿今日头条简单的刷新效果实例代码
点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据.有四个选项卡. 前两天导师要求做一个给本科学生预定机房座位的app,出发点来自这里.做着做着遇到很多问题,都解决了.这个效果感 ...
- android 仿微信头像裁剪,Android仿微信QQ设置图形头像裁剪功能
最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流. 而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue ...
- android标题栏不被顶上去,Android仿微信QQ聊天顶起输入法不顶起标题栏的问题
在这记录一下输入法弹出的一系列问题,有的输入法弹出就把整个布局弹上去,有的输入法弹出布局不会有变化,有的输入法弹出遮盖输入框等等问题,网上也有很多说加着加那的,但是看一下都不是很完整,解决不了所有问题 ...
- Android仿微信小视频录制功能(二)
Android仿微信小视频录制功能(二) 接着上一篇,在完成了录制功能后,伟大的哲学家沃兹基索德曾经说过:"有录就有放.",那么紧接着就来实现播放功能,按照国际惯例,先上下效果图: ...
- Android 高级UI解密 (四) :花式玩转贝塞尔曲线(波浪、轨迹变换动画)
讲解此UI系列必然少不了一个奇妙数学曲线-–贝塞尔曲线,它目前运用于App的范围是在太广了,最初的QQ气泡拖拽,到个人界面的波浪效果.Loading波浪效果,甚至于轨迹变化的动画都可以依赖贝塞尔曲线完 ...
- android 飘心动画(直播点赞)效果(二)---贝塞尔曲线的实现
上篇文章 android 飘心动画(直播点赞)效果 只有代码,没有相关的说明.因为我自己也没有看懂,所以参照网上另一篇关于贝塞尔曲线实现 飘心动画的效果,目的就是 便于理解上篇文章代码的思路,然后写个 ...
- Android 仿新版QQ的tab下面拖拽标记为已读的效果
可拖拽的红点,(仿新版QQ,tab下面拖拽标记为已读的效果),拖拽一定的距离可以消失回调. GitHub:DraggableFlagView(https://github.com/wangjiegul ...
最新文章
- 炼成优秀 SaaS 产品的三个要素?听腾讯、神策、网易的专家讲讲|PCon
- opencv 阈值分割 — threshold()
- java 字符串排序
- @AutoWired和@Resource注解异同分析
- SaltStack之salt-key管理
- python希尔排序的优缺点_Pythonの希尔排序
- git 获取远程分支到本地_如何将git本地仓库上传到远程仓库?
- 双层for循环时间复杂度_2 常见的时间复杂度实例
- 一段echats 饼状图刷新代码
- 异常检测3——AutoEncoder异常检测
- 跳跃回溯____寻找最长平台
- 程序开发基础学习五(json配置、解析文件,c++篇)
- 如何一键开通局域网共享
- 五边形镶嵌计算机程序,如何看待美国数学家发现可无缝密铺平面的五边形?.doc...
- Java—sql关于不同条件下合并结果
- iPad上用code-server运行VS Code
- 文件传输协议FTP/TFTP/SSH/SCP——应用层
- 【多目标进化优化】 MOEA 测试函数
- Shiro和SpringSecurity
- storyboard 苹果启动图_苹果App Store审核要求使用Storyboard启动界面的解决方案