一,實現思路
實現的效果:
此控件主要是模仿IReader打開書本翻轉以及放大特效,在看文章之前可以找本書來翻轉加深理解,呵呵,開個玩笑,進入正題。
實現的效果:
打開書本:
上層爲cover,下層爲content。cover播放放大翻轉動畫,content播放放大動畫。
幾個注意點:
1,動畫的播放只能侷限在父ViewGroup內部,放大到全屏該怎麼進行?
A:使用克隆體添加到WindowManager中,然後去播放動畫。
2,不能直接對WindowManager中的子控件播放動畫,該怎麼解決?
A:在WindowManger鋪滿一個AbsoluteLayout,然後再將克隆體cover添加到WindowManger中。
3,如果對任意位置的一張圖片,放大到全屏,讓位置剛好合適?
A:需要尋找到一個合適的縮放點。
二,具體實現
1,ContentScaleAnimation類,實現下層圖片的縮放。如何尋找縮放點?
上圖中
這裏只演示怎麼計算縮放點橫座標
x爲縮放點橫座標
pw爲parentWidth
ml爲marginLeft
w爲控件寬度
找到如下關係
縮放點到自身左邊距離/縮放點到父控件左邊的距離=縮放點自身右側距離/縮放點到父控件右邊的距離
(x-ml)/x=(w-(x-ml))/(pw-x)
計算得到x=ml*pw/(pw-w)
這裏提供方法:
private float resolvePivotX(float margingLeft, int parentWidth, int width) {
return (margingLeft * parentWidth) / (parentWidth - width);
}
package huwei.com.bookviewdemo;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* Created by jayce on 15-2-4.
*/
public class ContentScaleAnimation extends Animation {
private final float mFromX;
private final float mToX;
private final float mFromY;
private final float mToY;
private float mPivotX;
private float mPivotY;
private float mPivotXValue;
private float mPivotYValue;
private boolean mReverse;
public ContentScaleAnimation(float mFromX, float mToX, float mFromY, float mToY, float mPivotXValue, float mPivotYValue, boolean mReverse) {
this.mFromX = mFromX;
this.mToX = mToX;
this.mFromY = mFromY;
this.mToY = mToY;
this.mPivotXValue = mPivotXValue;
this.mPivotYValue = mPivotYValue;
this.mReverse = mReverse;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float sx = 1.0f;
float sy = 1.0f;
if (mFromX != 1.0f || mToX != 1.0f) {
sx = mReverse ? mToX + (mFromX - mToX) * interpolatedTime : mFromX + (mToX - mFromX) * interpolatedTime;
}
if (mFromY != 1.0f || mToY != 1.0f) {
sy = mReverse ? mToY + (mFromY - mToY) * interpolatedTime : mFromY + (mToY - mFromY) * interpolatedTime;
}
if (mPivotX == 0 && mPivotY == 0) {
t.getMatrix().setScale(sx, sy);
} else {
t.getMatrix().setScale(sx, sy, mPivotX, mPivotY);
}
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mPivotX = resolvePivotX(mPivotXValue, parentWidth, width);
mPivotY = resolvePivoY(mPivotYValue, parentHeight, height);
}
private float resolvePivotX(float margingLeft, int parentWidth, int width) {
return (margingLeft * parentWidth) / (parentWidth - width);
}
private float resolvePivoY(float marginTop, int parentHeight, int height) {
return (marginTop * parentHeight) / (parentHeight - height);
}
public void reverse() {
mReverse = !mReverse;
}
public boolean getMReverse() {
return mReverse;
}
}
,2,Rotate3DAnimation類,實現參考apiDemo中的Rotate3dAnimation,在此基礎上進行修改,實現翻轉和縮放動畫。
這裏需要繞Y軸旋轉180度,在翻轉前需要將物體移動到y軸上,然後再移回去。
matrix.preTranslate(-mPivotXValue, 0); //在進行rotateY之前需要移動物體,讓物體左邊與Y軸對齊
matrix.postTranslate(mPivotXValue, 0); //還原物體位置
package huwei.com.bookviewdemo;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* @author jayce
* @date 2015/2/3
*/
public class Rotate3DAnimation extends Animation {
private Camera mCamera;
private final float mFromDegrees;
private final float mToDegrees;
private final float mPivotXValue;
private final float mPivotYValue;
//private final float mDepthZ; //不需要用到此參數
private final float scaleTimes;
private boolean mReverse;
private float mPivotX; //縮放點X
private float mPivotY; //縮放點Y
/**
* cover 動畫構造方法,一邊放大,一邊翻轉
* @param mFromDegrees
* @param mToDegrees
* @param mPivotXValue 控件左上角X
* @param mPivotYValue 控件左上角Y
* @param scaleTimes 縮放比例
* @param mReverse 動畫是否逆向進行
*/
public Rotate3DAnimation(float mFromDegrees, float mToDegrees, float mPivotXValue, float mPivotYValue, float scaleTimes, boolean mReverse) {
this.mFromDegrees = mFromDegrees;
this.mToDegrees = mToDegrees;
this.mPivotXValue = mPivotXValue;
this.mPivotYValue = mPivotYValue;
this.scaleTimes = scaleTimes;
this.mReverse = mReverse;
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
mPivotX = resolvePivotX(mPivotXValue, parentWidth, width); //計算縮放點X
mPivotY = resolvePivoY(mPivotYValue, parentHeight, height); //計算縮放點Y
}
/**
* 執行順序 matrix.preTranslate() --> camera.rotateY(degrees) --> matrix.postTranslate() --> matrix.postScale()
* @param interpolatedTime
* @param t
*/
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float degrees = mReverse ? mToDegrees + (mFromDegrees - mToDegrees) * interpolatedTime : mFromDegrees + (mToDegrees - mFromDegrees) * interpolatedTime;
final Matrix matrix = t.getMatrix();
final Camera camera = mCamera;
camera.save();
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-mPivotXValue, 0); //在進行rotateY之前需要移動物體,讓物體左邊與Y軸對齊
matrix.postTranslate(mPivotXValue, 0); //還原物體位置
if (mReverse) {
matrix.postScale(1 + (scaleTimes - 1) * (1.0f - interpolatedTime), 1 + (scaleTimes - 1) * (1.0f - interpolatedTime), mPivotX, mPivotY);
} else {
matrix.postScale(1 + (scaleTimes - 1) * interpolatedTime, 1 + (scaleTimes - 1) * interpolatedTime, mPivotX, mPivotY);
}
}
private float resolvePivotX(float margingLeft, int parentWidth, int width) {
return (margingLeft * parentWidth) / (parentWidth - width);
}
private float resolvePivoY(float marginTop, int parentHeight, int height) {
return (marginTop * parentHeight) / (parentHeight - height);
}
public void reverse() {
mReverse = !mReverse;
}
public boolean getMReverse() {
return mReverse;
}
}
下載地址(4.0以及以下不支持) setX()導致動畫無法播放