一直都很喜歡Instagram的快拍(Story)功能,也很喜歡他們的翻轉效果,是一種簡單的3D翻轉效果。大體效果以下:java
貌似最近微博也出了一個差很少的Story的功能,用的翻轉動畫也是和Instagram同樣。android
看到這樣的效果,很容易想到用ViewPager的Transformer動畫來實現。固然這種翻轉效果網上也有相應的實現,就是以View的左邊或右邊爲旋轉軸進行空間上Y軸的旋轉。
因而很容易咱們能夠寫出下面的代碼git
public class StereoPagerTransformer implements ViewPager.PageTransformer {
private static final float MAX_ROTATE_Y = 90;
private final float pageWidth;
public StereoPagerTransformer(float pageWidth) {
this.pageWidth = pageWidth;
}
public void transformPage(View view, float position) {
view.setPivotY(view.getHeight() / 2);
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setPivotX(0);
view.setRotationY(90);
} else if (position <= 0) { // [-1,0]
view.setPivotX(pageWidth);
view.setRotationY(position * MAX_ROTATE_Y);
} else if (position <= 1) { // (0,1]
view.setPivotX(0);
view.setRotationY(position * MAX_ROTATE_Y);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setPivotX(0);
view.setRotationY(90);
}
}
}複製代碼
而後運行代碼看一下咱們實現的效果:github
額,總覺哪裏不對,嗯,就是動畫的速度不對,上面的寫法就是一個勻速進行的動畫,效果很是不理想,這時咱們就要從新寫一個插值器(TimeInterpolator ),在嘗試了系統自帶的差值器後,發現效果仍然不是很理想。因而決定本身寫一個插值器。less
根據TimeInterpolator代碼中的文檔能夠得知,插值器用於控制動畫進行的速度,其輸入值爲0~1,輸出值也爲0~1。ide
/** * A time interpolator defines the rate of change of an animation. This allows animations * to have non-linear motion, such as acceleration and deceleration. */
public interface TimeInterpolator {
/** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. * * @param input A value between 0 and 1.0 indicating our current point * in the animation where 0 represents the start and 1.0 represents * the end * @return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */
float getInterpolation(float input);
}複製代碼
通過簡單的分析,此次咱們的動畫應該在動畫前半段時進行緩慢一些(也就是輸入值在0到某個值之間),在後半段時(也就是輸入值在某個值到1之間)進行的快速一些。
通過簡單的調整,最終我寫了以下的插值器動畫
private static final TimeInterpolator sInterpolator = new TimeInterpolator() {
@Override
public float getInterpolation(float input) {
if (input < 0.7) {
return input * (float) pow(0.7, 3) * MAX_ROTATE_Y;
} else {
return (float) pow(input, 4) * MAX_ROTATE_Y;
}
}
};複製代碼
再次運行代碼,此次效果看上去好多了,哈哈,一個簡單又好看的效果就完成了。this
最後附上完整的代碼:spa
import android.animation.TimeInterpolator;
import android.support.v4.view.ViewPager;
import android.view.View;
import static java.lang.Math.pow;
/** * @author wupanjie */
public class StereoPagerTransformer implements ViewPager.PageTransformer {
private static final float MAX_ROTATE_Y = 90;
private static final TimeInterpolator sInterpolator = new TimeInterpolator() {
@Override
public float getInterpolation(float input) {
if (input < 0.7) {
return input * (float) pow(0.7, 3) * MAX_ROTATE_Y;
} else {
return (float) pow(input, 4) * MAX_ROTATE_Y;
}
}
};
private final float pageWidth;
public StereoPagerTransformer(float pageWidth) {
this.pageWidth = pageWidth;
}
public void transformPage(View view, float position) {
view.setPivotY(view.getHeight() / 2);
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setPivotX(0);
view.setRotationY(90);
} else if (position <= 0) { // [-1,0]
view.setPivotX(pageWidth);
view.setRotationY(-sInterpolator.getInterpolation(-position));
} else if (position <= 1) { // (0,1]
view.setPivotX(0);
view.setRotationY(sInterpolator.getInterpolation(position));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setPivotX(0);
view.setRotationY(90);
}
}
}複製代碼
動畫的靈魂在於它的插值器,插值器控制了動畫進行的速度,此次我選擇本身寫了一個插值器做爲練手,其實我此次寫的插值器效果仍不是很平滑,動畫的插值器也應該用貝塞爾曲線來製做,這樣咱們的動畫就會進行的更平滑。具體你們能夠參考自帶的PathInterpolator,是在API 21之後引入的,固然它也有對應的兼容包。
完整項目地址: github.com/wuapnjie/Da…3d