天天看點

android 水滴動畫效果圖,Android控件實作水滴效果

看到ios版上QQ重新整理效果像水滴,然後自己也想着去實作這樣的效果,這篇文章暫時沒有介紹下拉重新整理的效果,隻是單獨用一個控件來實作這樣的水滴效果。

效果圖如下:

android 水滴動畫效果圖,Android控件實作水滴效果

一、總體思路

1、畫兩個圓形,其中一個就是上面的大圓,還有一個是下面的小圓,大圓和小圓不斷變小,大圓的位置保持不變,小圓的位置不斷向下移動,即圓心不斷下移。

2、畫兩邊的曲線,這時候用到貝塞爾曲線去畫。

3、用屬性動畫實作動态的效果。

二、代碼實作

1、找出畫曲線的幾個關鍵點。

android 水滴動畫效果圖,Android控件實作水滴效果
android 水滴動畫效果圖,Android控件實作水滴效果

其實我是在第一張圖的基礎上,再在上面分别畫兩個圓,就可以得到第二張圖了。關鍵是畫出第一張圖。

(1)在這裡,p1,p2,p3,p4,這4個點分别對應兩個圓的兩邊的點,即p1到p2就是圓的直徑。p3和p4同理,那麼就很容易确定這四個點的坐标了。

(2)然後c1和c2是分别控制p1到p3、p2到p4的曲線,是貝塞爾曲線的控制點。它們的橫坐标對應的是p3,p4的橫坐标(相等),縱坐标取兩個圓心距離的一半。這樣畫出這個靜态的圖檔就不難了。

(3)畫上下兩個圓進去,就會變成第二張圖的效果。

2、在構造方法中調用init()初始化一些基本的變量

private void init(Context context, AttributeSet attrs) {

drawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG

| Paint.FILTER_BITMAP_FLAG);

paint = new Paint();

paint.setColor(fillColor);

// 轉換為像素機關

bigRadius = dip2px(context, bigRadius);

smallRadius = dip2px(context, smallRadius);

distance = dip2px(context, distance);

}

3、在onDraw()方法中畫水滴效果

要注意的是path需要重新new, 貝塞爾曲線的繪制,用到是path.quadTo這方法。具體可以看代碼。

@Override

protected void onDraw(Canvas canvas) {

// 必須重新new,不然路徑會重複,我之前就是這樣

path = new Path();

// 把畫布移到中心

canvas.translate(width / 2, height / 2);

// 從canvas層面去除繪制時鋸齒

canvas.setDrawFilter(drawFilter);

// 目前的兩個圓心的距離

currentDis = distance * fraction;

// 計算目前大圓的半徑

float bigRadius = this.bigRadius - currentDis / bigPercent;

float smallRadius = 0;

if (currentDis > 5) {// 距離大于5才改變小圓的半徑

smallRadius = this.smallRadius - currentDis / smallPercent;

}

// 大圓兩邊的兩個點坐标

leftX = -bigRadius;// 大圓目前的半徑

leftY = rightY = 0;

rightX = bigRadius;// 大圓目前的半徑

// 小圓兩邊的兩個點坐标

leftX2 = -smallRadius;// 小圓目前的半徑

leftY2 = rightY2 = currentDis;

rightX2 = -leftX2; // 小圓目前的半徑

// 兩個控制點

controlX1 = -smallRadius;// x坐标取小圓目前的半徑大小

controlY1 = currentDis / 2;// y坐标取兩個圓距離的一半

controlX2 = smallRadius;// x坐标取小圓目前的半徑大小

controlY2 = currentDis / 2;// y坐标取兩個圓距離的一半

path.moveTo(leftX, leftY);

path.lineTo(rightX, rightY);

// 用二階貝塞爾曲線畫右邊的曲線,參數的第一個點是右邊的一個控制點

path.quadTo(controlX2, controlY2, rightX2, rightY2);

path.lineTo(leftX2, leftY2);

// 用二階貝塞爾曲線畫左邊邊的曲線,參數的第一個點是左邊的一個控制點

path.quadTo(controlX1, controlY1, leftX, leftY);

// 畫大圓

canvas.drawCircle(0, 0, bigRadius, paint);

// 畫小圓

canvas.drawCircle(0, currentDis, smallRadius, paint);

// 畫path

canvas.drawPath(path, paint);

}

4、用屬性動畫,實作動态的效果。

public void perforAnim() {

ValueAnimator valAnimator = ObjectAnimator.ofFloat(0, 1);

valAnimator.addUpdateListener(new AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

fraction = (float) animation.getAnimatedValue();

postInvalidate();

}

});

valAnimator.setDuration(duration);

valAnimator.start();

}

5、重寫onMeasure()方法,處理wrap_content情況。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthSpectMode = MeasureSpec.getMode(widthMeasureSpec);

int widthSpectSize = MeasureSpec.getSize(widthMeasureSpec);

int heightSpectMode = MeasureSpec.getMode(heightMeasureSpec);

int heightSpectSize = MeasureSpec.getSize(heightMeasureSpec);

if (widthSpectMode == MeasureSpec.AT_MOST

&& heightSpectMode == MeasureSpec.AT_MOST) {

setMeasuredDimension(width, height);

} else if (widthSpectMode == MeasureSpec.AT_MOST) {

setMeasuredDimension(width, heightSpectSize);

} else if (heightSpectMode == MeasureSpec.AT_MOST) {

setMeasuredDimension(widthSpectSize, height);

}

}

6、其它的一些方法實作。

@Override

protected void onLayout(boolean changed, int left, int top, int right,

int bottom) {

super.onLayout(changed, left, top, right, bottom);

if (changed) {

width = right - left;

height = bottom - top;

}

}

public int dip2px(Context context, float dpValue) {

final float scale = context.getResources().getDisplayMetrics().density;

return (int) (dpValue * scale + 0.5f);

}

7、字段的定義

private final int fillColor = 0xff999999;// 填充顔色

private Paint paint;

private int width = 100, height = 300;// 預設寬高

float fraction = 0;// 比例值

/* 大圓半徑變化的比例 /

private final int bigPercent = 8;

/* 小圓半徑變化的比例 /

private final int smallPercent = 20;

// 動畫的執行時間

private long duration = 3000;

三、總結

一種動畫效果,應該先分析它的靜态的實作,然後添加動态的效果,這樣就比較容易實作它的動畫效果了。

以上就是本文的全部内容,希望對大家的學習有所幫助,也希望大家多多支援。