一,实现思路
实现的效果:
此控件主要是模仿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()导致动画无法播放