首页 技术 正文
技术 2022年11月20日
0 收藏 823 点赞 2,580 浏览 3695 个字

最近看需要做一款下拉刷新的效果,由于需要和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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,997
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,511
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,356
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,139
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,770
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,848