自定義view難免會接觸到動畫,不然很多效果做不出來,動畫分爲幾種,今天主要用到的是屬性動畫;
上面這個效果分上下兩部分完成,在繪製的時候先繪製下半部分,具體代碼如下,裏面有詳細註釋:
public class CameraAnimatorView extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 圖片左上padding值
private int mPadding = 300;
// 圖片寬高
private int mLength = 800;
// 上面翻的度數 (因爲要做動畫,所以先全部設置爲0,然後設置get,set方法爲動畫做準備)
float topFlip = 0;
// 下面翻的度數
float bottomFlip = 0;
// 旋轉度數
float flipRotation = 0;
/*
android.graphics.Camera ( 是這個並不是相機,相機是android.hardware.Camera )
官方介紹:A camera instance can be used to compute 3D transformations and generate a matrix that can be applied, for instance, on aCanvas.
(自己隨便翻譯吧)
Camera對象可以用來計算3D變換,並將計算結果封裝進一個Matrix矩陣,之後便進行應用
*/
Camera camera = new Camera();
public CameraAnimatorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
{
/*
默認0,0,-8 ( 8 英寸 = 8 * 72 像素 )
每個手機分辨率不同,所以需要做適配 ,getResources().getDisplayMetrics().density
*/
camera.setLocation(0, 0, -6 * getResources().getDisplayMetrics().density);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 先繪製下半部分,再繪製上半部分(直接複製)
/*********************************繪製上半部分*******************************************/
canvas.save();
canvas.translate(mPadding + mLength / 2, mPadding + mLength / 2);
canvas.rotate(-flipRotation);
camera.save();
// 以X軸爲軸心旋轉*°
camera.rotateX(topFlip);
camera.applyToCanvas(canvas);
camera.restore();
canvas.clipRect(-mLength , -mLength , mLength, 0);
canvas.rotate(flipRotation);
canvas.translate(-(mPadding + mLength / 2), -(mPadding + mLength / 2));
canvas.drawBitmap(getAvatar(mLength), mPadding, mPadding, mPaint);
canvas.restore();
/**********************************繪製下半部分(倒着繪製)******************************/
canvas.save();
/*
投射原點再0,0位置,如果不移動畫布,映射出來的是變形的圖片(歪的),所以需要先移動再旋轉再挪回來
挪動位置:padding + 圖片寬高的一半
*/
canvas.translate(mPadding + mLength / 2, mPadding + mLength / 2);
canvas.rotate(-flipRotation);
// 保存狀態
camera.save();
// 以X軸爲軸心旋轉*°
camera.rotateX(bottomFlip);
// 應用到畫布 根據當前的變換計算出相應的矩陣,然後應用到制定的畫布上
camera.applyToCanvas(canvas);
// 回滾狀態
camera.restore();
// 只要下半部分,旋轉前切割 因爲涉及到旋轉,所以切割範圍要變大
canvas.clipRect(-mLength, 0, mLength, mLength);
// 旋轉20°
canvas.rotate(flipRotation);
// 將畫布移回來
canvas.translate(-(mPadding + mLength / 2), -(mPadding + mLength / 2));
// 繪製圖片
canvas.drawBitmap(
getAvatar(mLength),
mPadding, mPadding,
mPaint
);
canvas.restore();
}
// 自定義動畫配置 topFlip,bottomFlip,FlipRotation
public float getTopFlip() {
return topFlip;
}
public void setTopFlip(float topFlip) {
this.topFlip = topFlip;
invalidate();
}
public float getBottomFlip() {
return bottomFlip;
}
public void setBottomFlip(float bottomFlip) {
this.bottomFlip = bottomFlip;
invalidate();
}
public float getFlipRotation() {
return flipRotation;
}
public void setFlipRotation(float flipRotation) {
this.flipRotation = flipRotation;
invalidate();
}
Bitmap getAvatar(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
// inJustDecodeBounds爲true,不返回bitmap,只返回這個bitmap的尺寸
options.inJustDecodeBounds = true;
// 從資源中讀取(比較浪費資源,所以上面設置爲true,只獲取圖片寬高)
BitmapFactory.decodeResource(getResources(), R.drawable.ysdry, options);
// 再設置爲false,最後要返回bitmap
options.inJustDecodeBounds = false;
// 根據縮放比例重新計算寬高
options.inDensity = options.outWidth;
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.drawable.ysdry, options);
}
}
下面是開啓動畫
/*
屬性動畫 大概分爲兩種,ViewPropertyAnimator 和 ObjectAnimator
前者是系統提供好的,可做一些簡單的平移,縮放,旋轉,漸變
後者是自定義屬性動畫,比較靈活
*/
CameraAnimatorView mCameraAnimatorView = findViewById(R.id.mCameraAnimatorView);
// bottomFlip對應CameraAnimatorView裏面的bottomFlip,45代表bottomFlip要變化的值
ObjectAnimator bottomAnimator=ObjectAnimator.ofFloat(mCameraAnimatorView,"bottomFlip",45);
// 設置時長
bottomAnimator.setDuration(1500);
ObjectAnimator flipRotationAnimator=ObjectAnimator.ofFloat(mCameraAnimatorView,"flipRotation",270);
flipRotationAnimator.setDuration(1500);
ObjectAnimator topFlipAnimator=ObjectAnimator.ofFloat(mCameraAnimatorView,"topFlip",-45);
flipRotationAnimator.setDuration(3300);
// 多個動畫,分先後順序填寫到playSequentially方法中
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(bottomAnimator,flipRotationAnimator,topFlipAnimator);
// 延遲動畫啓動的時間
animatorSet.setStartDelay(2000);
animatorSet.start();