Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果

這篇文章給大家分享的是有關(guān)Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的華亭網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

1.上原圖

前幾天在 Hencoder 征稿看到的Filpboard 里的的動(dòng)畫效果:

Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果

Filipboard.gif

先bb一句:在看本文的同時(shí),如果覺得我寫的模糊看不太懂的可以直接拉到文末,配合完整代碼再一步一步看。

2.實(shí)現(xiàn) 整體思路:

用手機(jī)拍下來,逐幀觀看了許久,恍然大悟,就是一張紙,折起一邊之后,讓其對(duì)折線繞中心點(diǎn)旋轉(zhuǎn)。

關(guān)聯(lián)自定義 ViewCamera 來控制對(duì)折幅度, canves 控制旋轉(zhuǎn)。

具體:

每當(dāng)對(duì)折線旋轉(zhuǎn)的時(shí)候,圖標(biāo)總是一邊是折起來的,一邊是平鋪的,且中心對(duì)稱,所以將它整體分為兩部分來繪制。

使用 canvesClipRect() 方法可以輕松實(shí)現(xiàn)切割畫布。

應(yīng)該也能順著想到給 canves 做動(dòng)畫讓折疊線(切割線)動(dòng)起來,這里會(huì)有一個(gè)問題,即:對(duì)折線是動(dòng)起來了,可繪制內(nèi)容也會(huì)跟著動(dòng)起來,那我們要的是只有分割線在中間旋轉(zhuǎn)實(shí)時(shí)分割圖標(biāo),所以有個(gè)小技巧,

先這樣:

canvas.rotate(-degreeZ);
 canvas.clipRect(0, -centerY, centerX, centerY);

再這樣:

canvas.rotate(degreeZ);
 canvas.drawBitmap(bitmap, x, y, paint);

嗯對(duì),在旋轉(zhuǎn)畫板的代碼之后做切割,切割之后呢又讓他以完全相同的角度反向旋轉(zhuǎn),再繪制圖標(biāo),這樣就可以實(shí)現(xiàn)之前讓切割線旋轉(zhuǎn),而圖標(biāo)不動(dòng)的目的了。

先貼這部分代碼,明天寫剩余部分:

protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 int bitmapWidth = bitmap.getWidth();
 int bitmapHeight = bitmap.getHeight();
 int centerX = getWidth() / 2;
 int centerY = getHeight() / 2;
 int x = centerX - bitmapWidth / 2;
 int y = centerY - bitmapHeight / 2;
 // 不動(dòng)的另一部分
  canvas.save();
 canvas.translate(centerX, centerY);
 canvas.rotate(-degreeZ);
 canvas.clipRect(-centerX, -centerY, 0, centerY);
 canvas.rotate(degreeZ);
 canvas.translate(-centerX, -centerY);
 canvas.drawBitmap(bitmap, x, y, paint);
  canvas.restore();
}

這時(shí)候看到的效果應(yīng)該是這樣的:

Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果

切割線旋轉(zhuǎn)

接下來寫和它中心對(duì)稱的另一半:

因?yàn)槭侵行膶?duì)稱,旋轉(zhuǎn)速度一致,只需要變更切割的部分為對(duì)稱部分,所以這部分代碼只需要將前一部分代碼復(fù)制然后修改這一行 :

canvas.clipRect(-centerX, -centerY, 0, centerY);

為:

canvas.clipRect(0,-centerY,centerX,centerY);

就可以實(shí)現(xiàn)目的。

完整代碼:

protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int x = centerX - bitmapWidth / 2;
int y = centerY - bitmapHeight / 2;
 // 不動(dòng)的另一部分
 canvas.save();
 canvas.translate(centerX, centerY);
 canvas.rotate(-degreeZ);
 canvas.clipRect(-centerX, -centerY, 0, centerY);
 canvas.rotate(degreeZ);
 canvas.translate(-centerX, -centerY);
 canvas.drawBitmap(bitmap, x, y, paint);
 canvas.restore();
 // 被折起來的另一部分
 canvas.save();
 canvas.translate(centerX,centerY);
 canvas.rotate(-degreeZ);
 canvas.clipRect(0,-centerY,centerX,centerY);
 canvas.rotate(degreeZ);
 canvas.translate(-centerX,-centerY);
 canvas.drawBitmap(bitmap,x,y,paint);
 canvas.restore();
}

這時(shí)候運(yùn)行代碼的效果就是 沒有效果。因?yàn)槲覀兝L制的兩部分一直是中心對(duì)稱,雖然我們知道它在動(dòng),但是看起來仿佛只是繪制了一張靜態(tài)的圖標(biāo)。

不著急,這時(shí)候就需要給它對(duì)折起來的這一半加上 Camera ,讓它 “折起來”。

在代碼里添加 Camera 經(jīng)典四步:

camera.save();
 camera.rotateY(degreeY);
 camera.applyToCanvas(canvas);
 camera.restore();

當(dāng)然不考慮直接加上這些代碼是不行的,因?yàn)槲覀兪?quot;對(duì)折",意味著 折起來的部分也要和 切割線 同步旋轉(zhuǎn),

所以這些代碼應(yīng)該這樣插入進(jìn)去:

// 被折起來的另一部分
 canvas.save();
 camera.save();
 canvas.translate(centerX, centerY);
 canvas.rotate(-degreeZ);
 camera.rotateY(degreeY);
 camera.applyToCanvas(canvas);
 canvas.clipRect(0, -centerY, centerX, centerY);
 canvas.rotate(degreeZ);
 canvas.translate(-centerX, -centerY); 
 canvas.drawBitmap(bitmap, x, y, paint);
 camera.restore(); 
 canvas.restore();

這時(shí)候再運(yùn)行代碼:

Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果

已然完成百分之80

嘿,原動(dòng)畫的要求已經(jīng)完成80%了?,F(xiàn)在去加上最后的動(dòng)畫: 之前不動(dòng)的一半也被折起來了,這個(gè)很簡單修改不動(dòng)的那一部分的代碼:

// 不動(dòng)的另一部分
 canvas.save();
 camera.save();
 canvas.translate(centerX, centerY);
 canvas.rotate(-degreeZ);
 canvas.clipRect(-centerX, -centerY, 0, centerY);
 canvas.rotate(degreeZ);
 camera.rotateX(degreeY2);
 camera.applyToCanvas(canvas);
 canvas.translate(-centerX, -centerY);
 canvas.drawBitmap(bitmap, x, y, paint);
 camera.restore();
 canvas.restore();

運(yùn)行代碼,ok,完成~

對(duì)了,還有個(gè)細(xì)節(jié),仔細(xì)觀察發(fā)現(xiàn) 中間旋轉(zhuǎn)動(dòng)畫旋轉(zhuǎn)速度 越來越 的,所以使用 LinearOutSlowInInterpolator 這個(gè)插補(bǔ)器。

關(guān)于屬性動(dòng)畫,還有后面的更多的定制性以及細(xì)節(jié)優(yōu)化,比如重寫 onMeasure() ,動(dòng)畫屬性抽離就不說了,整體思路以及一些細(xì)節(jié)思考我感覺都講出來了,不知道是不是只有我一個(gè)人懂的那種。好懶啊,想睡覺。想下班,想吃雞。

Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果

完成版

最后推薦一下大佬 扔物線 的學(xué)習(xí)網(wǎng)站 hencoder :http://hencoder.com/ 不僅免費(fèi),而且賊6~

雖然我猜也沒多少人能堅(jiān)持看到這里,好慘,捂臉。

項(xiàng)目碼云地址:  https://gitee.com/alucode/AsFilpBoard

完整代碼:

public class FlipBoardView extends View {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap bitmap;
private Camera camera = new Camera();
int degreeZ;
int degreeY;
int degreeY2;
//中間旋轉(zhuǎn)動(dòng)畫
private ObjectAnimator animator = ObjectAnimator.ofInt(this, "degreeZ", 0, 270);
//第一段折起動(dòng)畫
private ObjectAnimator animator1 = ObjectAnimator.ofInt(this, "degreeY", 0, -45);
//最后一段折起動(dòng)畫
private ObjectAnimator animator2 = ObjectAnimator.ofInt(this, "degreeY2", 0, -45);
AnimatorSet animatorSet;
public FlipBoardView(Context context) {
 super(context);
}
public FlipBoardView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
}
public FlipBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
}
{
 //糊臉修正,給camera 做z軸距離適配,避免繪制糊臉
 DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
 float newZ = -displayMetrics.density * 6;
 camera.setLocation(0, 0, newZ);
 bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.maps);
 animator.setDuration(1000);
 animator.setStartDelay(500);
 animator.setInterpolator(new LinearOutSlowInInterpolator());
 animator1.setDuration(800);
 animator1.setStartDelay(500);
 animator1.setInterpolator(new LinearInterpolator());
 animator2.setDuration(500);
 animator2.setStartDelay(500);
 animator2.setInterpolator(new LinearInterpolator());
 animatorSet = new AnimatorSet();
 animatorSet.playSequentially(animator1, animator, animator2);
 animatorSet.addListener(new AnimatorListenerAdapter() {
 @Override
 public void onAnimationEnd(Animator animation) {
  super.onAnimationEnd(animation);
  try {
  Thread.sleep(500);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  degreeZ = 0;
  degreeY = 0;
  degreeY2 = 0;
  animatorSet.start();
 }
 });
}
@Override
protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 animatorSet.start();
}
@Override
protected void onDetachedFromWindow() {
 super.onDetachedFromWindow();
 animatorSet.end();
}
@SuppressWarnings("unused")
public void setDegreeZ(int degreeZ) {
 this.degreeZ = degreeZ;
 invalidate();
}
@SuppressWarnings("unused")
public void setDegreeY(int degreeY) {
 this.degreeY = degreeY;
 invalidate();
}
public void setDegreeY2(int degreeY2) {
 this.degreeY2 = degreeY2;
 invalidate();
}
/**
 * 原理:從折 線分為兩部分繪制,其實(shí)是繪制了兩個(gè)bitmap 一個(gè)動(dòng)一個(gè)不動(dòng) 然后截取拼湊
 *
 * @param canvas ca
 */
@Override
protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 int bitmapWidth = bitmap.getWidth();
 int bitmapHeight = bitmap.getHeight();
 int centerX = getWidth() / 2;
 int centerY = getHeight() / 2;
 int x = centerX - bitmapWidth / 2;
 int y = centerY - bitmapHeight / 2;
 canvas.save();
 camera.save();
 canvas.translate(centerX, centerY);
 canvas.rotate(-degreeZ);
 camera.rotateY(degreeY);
 camera.applyToCanvas(canvas);
 canvas.clipRect(0, -centerY, centerX, centerY);
 canvas.rotate(degreeZ);
 canvas.translate(-centerX, -centerY);
 canvas.drawBitmap(bitmap, x, y, paint);
 camera.restore();
 canvas.restore();
// 不動(dòng)的另一部分
 canvas.save();
 camera.save();
 canvas.translate(centerX, centerY);
 canvas.rotate(-degreeZ);
 canvas.clipRect(-centerX, -centerY, 0, centerY);
 canvas.rotate(degreeZ);
 camera.rotateX(degreeY2);
 camera.applyToCanvas(canvas);
 canvas.translate(-centerX, -centerY);
 canvas.drawBitmap(bitmap, x, y, paint);
 camera.restore();
 canvas.restore();
}
/**
 * onMeasure() 日常重寫
 * @param widthMeasureSpec w
 * @param heightMeasureSpec h
 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 int width;
 int height;
 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 int heightSize = MeasureSpec.getSize(heightMeasureSpec);
 if (widthMode == MeasureSpec.EXACTLY) {
 width = widthSize;
 } else {
 width = getPaddingLeft() + bitmap.getWidth() + getPaddingRight();
 }
 if (heightMode == MeasureSpec.EXACTLY) {
 height = heightSize;
 } else {
 height = getPaddingTop() + bitmap.getHeight() + getPaddingBottom();
 }
 setMeasuredDimension(width, height);
}
}

感謝各位的閱讀!關(guān)于“Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

文章名稱:Android如何實(shí)現(xiàn)仿Flipboard動(dòng)畫效果
網(wǎng)頁URL:http://muchs.cn/article4/joosie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、移動(dòng)網(wǎng)站建設(shè)、小程序開發(fā)、企業(yè)網(wǎng)站制作、網(wǎng)站設(shè)計(jì)公司、域名注冊

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)