最近看需要做一款下拉刷新的效果,由于需要和Ios界面保持一致,所以这用安卓的方式实现了ios下的下拉刷新的粘虫效果。

最新的安卓手机版本的QQ也有这种类似的效果,就是拖动未读信息的那个红色圆圈,拖动近距离的是就有这种粘虫的效果。

下面是安卓版本的嘟嘟App的效果截图,后面会简单的介绍下的实现原理

原理:

如下图所示,在没有进行下拉的是,显示的是A图,实际上是一个圆形,当进行向下的拖动的时候,圆形会进行拉伸,这里简单用模拟下圆形被用力拉伸的效果。

1、被拉伸的圆形,实际上分为3部分,上面的部分(是个半圆,稍微大点,简称为大圆),中间部分(是一个拉伸的部分,有2条平滑的曲线),下面部分(也是一个半圆,较小,成为小圆)

2、当滑动的距离越来越大的时候,模拟的力就越大,那么圆就拉伸越厉害。这样我们可以把上面的大圆和下面的小圆变的越来越小。中间部分,变成的越来越长。

3、拖动过程理解,那么简述下绘制的流程,从1点开始绘制,1~2是一个四分之一的圆形,2~3是一个曲线,我们可以用贝塞尔曲线来绘制,具体贝塞尔是什么东西,可以自行百度,这里不做解释。3~4是一个半圆,4~5和2~3一样,也是一个贝塞尔曲线。5~1和1~2一样也是四分之一的圆形。

上面就是简单原理,可能实际效果还是需要优化的,不过原理再次,后面只需要慢慢优化即可,当初实现这个功能也是费了2天时间。

下面是代码片段,具体完整代码,后面会给出下载链接。

public class RefreshView extends View {

	static final int BEZIER_OFFSET = McDimenUtil.dp2Px(15);// 贝塞尔曲线的偏移值
static final int R = McDimenUtil.dp2Px(30); // 圆球的半径
static final int Y_OFFSET = McDimenUtil.dp2Px(60); // 竖直方向最大的偏移值 int currentX;
int currentY;
private boolean isReFreshed;
private int offsetY;
private OnPullRefreshCallback onPullRefreshCallback;
private Paint paint;
private Path path;
int startX;
int startY; public RefreshView(Context paramContext) {
super(paramContext);
init();
} public RefreshView(Context paramContext, AttributeSet paramAttributeSet) {
super(paramContext, paramAttributeSet);
init();
} public RefreshView(Context paramContext, AttributeSet paramAttributeSet, int paramInt) {
super(paramContext, paramAttributeSet, paramInt);
init();
} static void addBcr(Path paramPath, int x1, int y1, int x2, int y2, float rate) {
int i = (int) (rate * BEZIER_OFFSET);
int cx = (x2 + x1) / 2 - i; // 控制点xs
int cy = (y2 + y1) / 2 - i; // 控制点y
paramPath.quadTo(cx, cy, x2, y2);
} static void addBcr2(Path paramPath, int x1, int y1, int x2, int y2, float rate) {
int i = (int) (rate * BEZIER_OFFSET);
int cx = (x2 + x1) / 2 + i; // 控制点xs
int cy = (y2 + y1) / 2 - i; // 控制点y
paramPath.quadTo(cx, cy, x2, y2);
} public void draw(Canvas paramCanvas) {
super.draw(paramCanvas);
update(paramCanvas);
} void init() {
this.path = new Path();
this.paint = new Paint();
this.paint.setAntiAlias(true);
this.paint.setColor(Color.parseColor("#2baaff"));
} public boolean onTouchEvent(MotionEvent event) {
currentX = (int) event.getX();
currentY = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = currentX;
startY = currentY;
break;
case MotionEvent.ACTION_MOVE:
// 计算偏移值,然后重新绘制
setOffsetY(currentY - startY);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// 重置界面
setOffsetY(0);
startX = startY = currentY = currentX = 0;
break;
}
return true; // super.onTouchEvent(event);
} public boolean isReFreshed() {
return this.isReFreshed;
} public void setOffsetY(int offset) {
this.offsetY = offset;
if (offsetY >= 0) {
invalidate();
}
} void update(Canvas paramCanvas) {
this.path.reset();
int width = getWidth();
int height = getHeight();
float rate = 1.0F * this.offsetY / height;
int r = (int) (R * (1.0F - rate)); // 圆球的半径,动态改变的,当拖拉的时候,r的会根据距离改变,进行变化 this.path.moveTo(width / 2, 0.0F);// 移动到(width/2 , 0)这个点 this.path.arcTo(new RectF(width / 2 - r, 0.0F, r + width / 2, r * 2), -90.0F, 90.0F);
// 根据半径r,换出一个四分之一的圆形 int m = (int) (9.0F * (rate * r));// 算出底部的校园与上面的大圆的圆心的距离
if ((m > Y_OFFSET) && (this.onPullRefreshCallback != null)) { // 如果这个距离超过了限制,则可以出发回调
this.onPullRefreshCallback.onCallback();
this.isReFreshed = true;
invalidate();
// return;
} this.isReFreshed = false;
int x2 = (int) (r + width / 2 - rate * r); // 小圆的水平的直径右边的点x坐标
int y = r + m; // 小圆的圆心坐标,y坐标
int x1 = (int) (width / 2 - r + rate * r);// 小圆的水平的直径左边的点x坐标
// 绘制一个贝塞尔曲线
addBcr(this.path, r + width / 2, r, x2, y, rate); int r2 = (x2 - x1) / 2; // 小圆的半径
// 绘制一个半圆
this.path.arcTo(new RectF(x1, y - r2, x2, y + r2), 0.0F, 180.0F); // 绘制一个贝塞尔曲线
addBcr2(this.path, x1, y, width / 2 - r, r, rate); // 在绘制上面的一个四分之一园
this.path.arcTo(new RectF(width / 2 - r, 0.0F, r + width / 2, r * 2), 180.0F, 90.0F); this.path.setFillType(Path.FillType.WINDING);
paramCanvas.drawPath(this.path, this.paint);
} public void setOnPullRefreshCallback(OnPullRefreshCallback callback) {
this.onPullRefreshCallback = callback;
} public static abstract interface OnPullRefreshCallback {
public abstract void onCallback();
}
}

运行效果:

完整代码下载地址:

地址

http://download.csdn.net/detail/xia215266092/8107081

高仿IOS下拉刷新的粘虫效果的更多相关文章

  1. 仿IOS中下拉刷新的“雨滴”效果

    在IOS中,有非常赞的"水滴"下拉效果.非常久之前也想在Android上实现,可是苦于能力有限,一直未能付诸行动.这几天趁着空隙时间.写了一版初步实现,基本达到了"水滴& ...

  2. 使用 CSS overscroll-behavior 控制滚动行为:自定义下拉刷新和溢出效果

    CSS 的新属性 overscroll-behavior 允许开发者覆盖默认的浏览器滚动行为,一般用在滚动到顶部或者底部. 背景 滚动边界和滚动链接(boundary & chaining) ...

  3. iOS下拉刷新和上拉刷新

    在iOS开发中,我们经常要用到下拉刷新和上拉刷新来加载新的数据,当前这也适合分页.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 上拉刷新 1.在TableView里,一打开软件, ...

  4. Android自定义控件之仿美团下拉刷新

    美团的下拉刷新分为三个状态: 第一个状态为下拉刷新状态(pull to refresh),在这个状态下是一个绿色的椭圆随着下拉的距离动态改变其大小. 第二个部分为放开刷新状态(release to r ...

  5. iOS 下拉刷新-上拉加载原理

    前言 讲下拉刷新及上拉加载之前先给大家解释UIScrollView的几个属性 contentSize是UIScrollView可以滚动的区域. contentOfinset 苹果官方文档的解释是&qu ...

  6. iOS 下拉刷新和加载更多 (OC\Swift)

    Swift语言出来之后, 可能还没有第三方的下拉刷新和上提加载, 所以自己用UIRefreshControl控件和UITableView实例的tableFooterView(底部视图)属性结合起来写了 ...

  7. iOS 下拉刷新 上拉加载实现原理

    1.下拉刷新 实现原理 if (scrollView.contentOffset.y < -100) { [UIView animateWithDuration:1.0 animations:^ ...

  8. 用vue写一个仿app下拉刷新的组件

    如果你用vue弄移动端的页面,那么下拉刷新还是比较常见的场景,下面来研究如何写一个下拉刷新的组件(先上图); 由于节省大家的时间,样式就不贴出来了. html结构也不必介绍了,直接看代码吧-.- &l ...

  9. iOS:下拉刷新控件UIRefreshControl的详解

    下拉刷新控件:UIRefreshControl 1.具体类信息: @interface UIRefreshControl : UIControl //继承控制类 - (instancetype)ini ...

随机推荐

  1. part1:15-安装Linux系统到开发板

    1.Qtopia简介 Qtopia是Trolltech公司为采用嵌入式Linux操作系统的消费电子设备而开发的综合应用平台,Qtopia包含完整的应用层.灵活的界面用户.窗口操作系统.应用程序启动程序 ...

  2. window.load 和$(document).ready() 、window.load和body onload区别

    1.执行时间 window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行. $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕.2.编写个数不同 w ...

  3. 【Mac】使用PicGIF制作gif动态图片

    动态图片是我们常常需要的,mac系统下制作gif图片,可以使用PicGIF,AppStore中有一个简单版本免费的 环境与工具 1.mac系统 2.PicGIF Lite(可以在AppStore下载) ...

  4. window server2012服务器上如何安装nginx并启动

    window环境下,Nginx安装启动的步骤如下: 把下载的window下的安装包,解压到一个不包含空格的路径下,比如:d:/Nginx 打开命令行窗口[win+R 输入cmd,然后确定]. 进入解压 ...

  5. 美团点评2017校招笔试真题-算法工程师B

    美团点评2017校招笔试真题-算法工程师B 1.以下关于经典的k-means聚类的说法哪个是错误的? A:k-means聚类算法是全局收敛的 B:k-means的聚类结果和初始聚类中心点的选取有关 C ...

  6. Django基础(二)

    https://www.cnblogs.com/yuanchenqi/articles/5716193.html

  7. Linux抓包

    默认系统里边没有安装有tcpdump的,无法直接使用   这里我们可以使用yum来直接安装它 yum install -y tcpdump   如果忘记了这个软件的用法,我们可以使用 tcpdump ...

  8. 学习前端的菜鸡对JS的call,apply,bind的通俗易懂理解

       call,apply,bind 在JavaScript中,call.apply和bind是Function对象自带的三个方法,都是为了改变函数体内部 this 的指向.            a ...

  9. 7) mvn dependency:tree

    http://maven.apache.org/plugins/maven-dependency-plugin/tree-mojo.html mvn dependency:tree 查看 <de ...

  10. Spring bean是如何加载的

    Spring bean是如何加载的 加载bean的主要逻辑 在AbstractBeanFactory中doGetBean对加载bean的不同情况进行拆分处理,并做了部分准备工作 具体如下 获取原始be ...