高仿IOS下拉刷新的粘蟲效果
來自: http://blog.csdn.net//guijiaoba/article/details/40663815
最近看需要做一款下拉刷新的效果,由于需要和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
本文由用戶 smallguang 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!