高仿IOS下拉刷新的粘蟲效果

最近看須要作一款下拉刷新的效果,因爲須要和Ios界面保持一致,因此這用安卓的方式實現了ios下的下拉刷新的粘蟲效果。java

最新的安卓手機版本的QQ也有這種相似的效果,就是拖動未讀信息的那個紅色圓圈,拖動近距離的是就有這種粘蟲的效果。ios



下面是安卓版本的嘟嘟App的效果截圖,後面會簡單的介紹下的實現原理優化

 





原理:this

以下圖所示,在沒有進行下拉的是,顯示的是A圖,其實是一個圓形,當進行向下的拖動的時候,圓形會進行拉伸,這裏簡單用模擬下圓形被用力拉伸的效果。.net

一、被拉伸的圓形,實際上分爲3部分,上面的部分(是個半圓,稍微大點,簡稱爲大圓),中間部分(是一個拉伸的部分,有2條平滑的曲線),下面部分(也是一個半圓,較小,成爲小圓)code

二、當滑動的距離愈來愈大的時候,模擬的力就越大,那麼圓就拉伸越厲害。這樣咱們能夠把上面的大圓和下面的小圓變的愈來愈小。中間部分,變成的愈來愈長。blog

三、拖動過程理解,那麼簡述下繪製的流程,從1點開始繪製,1~2是一個四分之一的圓形,2~3是一個曲線,咱們能夠用貝塞爾曲線來繪製,具體貝塞爾是什麼東西,能夠自行百度,這裏不作解釋。3~4是一個半圓,4~5和2~3同樣,也是一個貝塞爾曲線。5~1和1~2同樣也是四分之一的圓形。ip


上面就是簡單原理,可能實際效果仍是須要優化的,不過原理再次,後面只須要慢慢優化便可,當初實現這個功能也是費了2天時間。get


下面是代碼片斷,具體完整代碼,後面會給出下載連接。it


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

相關文章
相關標籤/搜索