• 高仿IOS下拉刷新的粘虫效果


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




  • 相关阅读:
    测试用例原理以及设计方法
    软件测试方法大汇总(转)
    黑盒测试用例大集
    博客第一篇章
    什么是Shell脚本
    部署 Django
    Django 国际化和本地化
    Django与CSRF 、AJAX
    认证系统 Authentication
    Django与缓存
  • 原文地址:https://www.cnblogs.com/liushuibufu/p/4140910.html
Copyright © 2020-2023  润新知