【发布时间】:2011-10-16 16:25:48
【问题描述】:
我使用this android tutorial 创建了视图的 3D 翻转 但是,我已经以编程方式完成了它,如果可能的话,我想在 xml 中完成这一切。我说的不是简单地将视图缩小到中间然后退出,而是实际的 3D 翻转。
这可以通过 xml 实现吗?
【问题讨论】:
我使用this android tutorial 创建了视图的 3D 翻转 但是,我已经以编程方式完成了它,如果可能的话,我想在 xml 中完成这一切。我说的不是简单地将视图缩小到中间然后退出,而是实际的 3D 翻转。
这可以通过 xml 实现吗?
【问题讨论】:
这是答案,尽管它仅适用于 3.0 及更高版本。
1) 创建一个名为“animator”的新资源文件夹。
2) 创建一个新的 .xml 文件,我将其称为“翻转”。使用以下 xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0" android:valueTo="360" android:propertyName="rotationY" >
</objectAnimator>
不,objectAnimator 标签不以大写“O”开头。
3) 使用以下代码启动动画:
ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(mContext, R.animator.flipping);
anim.setTarget(A View Object reference goes here i.e. ImageView);
anim.setDuration(3000);
anim.start();
这一切都是从here 那里得到的。
【讨论】:
由于这个问题的答案已经过时,这里有一个更现代的解决方案,它依赖于 ValueAnimators。 这个解决方案实现了一个真正的、视觉上吸引人的 3D 翻转,因为它不仅翻转视图,而且在翻转的同时对其进行缩放(Apple 就是这样做的)。
首先我们设置 ValueAnimator:
mFlipAnimator = ValueAnimator.ofFloat(0f, 1f);
mFlipAnimator.addUpdateListener(new FlipListener(frontView, backView));
以及对应的更新监听器:
public class FlipListener implements ValueAnimator.AnimatorUpdateListener {
private final View mFrontView;
private final View mBackView;
private boolean mFlipped;
public FlipListener(final View front, final View back) {
this.mFrontView = front;
this.mBackView = back;
this.mBackView.setVisibility(View.GONE);
}
@Override
public void onAnimationUpdate(final ValueAnimator animation) {
final float value = animation.getAnimatedFraction();
final float scaleValue = 0.625f + (1.5f * (value - 0.5f) * (value - 0.5f));
if(value <= 0.5f){
this.mFrontView.setRotationY(180 * value);
this.mFrontView.setScaleX(scaleValue);
this.mFrontView.setScaleY(scaleValue);
if(mFlipped){
setStateFlipped(false);
}
} else {
this.mBackView.setRotationY(-180 * (1f- value));
this.mBackView.setScaleX(scaleValue);
this.mBackView.setScaleY(scaleValue);
if(!mFlipped){
setStateFlipped(true);
}
}
}
private void setStateFlipped(boolean flipped) {
mFlipped = flipped;
this.mFrontView.setVisibility(flipped ? View.GONE : View.VISIBLE);
this.mBackView.setVisibility(flipped ? View.VISIBLE : View.GONE);
}
}
就是这样!
完成此设置后,您可以通过调用来翻转视图
mFlipAnimator.start();
并通过调用来反转翻转
mFlipAnimator.reverse();
如果要检查视图是否翻转,实现并调用该函数:
private boolean isFlipped() {
return mFlipAnimator.getAnimatedFraction() == 1;
}
您还可以通过实现此方法检查视图当前是否正在翻转:
private boolean isFlipping() {
final float currentValue = mFlipAnimator.getAnimatedFraction();
return (currentValue < 1 && currentValue > 0);
}
你可以结合上面的函数来实现一个很好的函数来切换翻转,这取决于它是否被翻转:
private void toggleFlip() {
if(isFlipped()){
mFlipAnimator.reverse();
} else {
mFlipAnimator.start();
}
}
就是这样!简单易行。享受吧!
【讨论】:
我创建了一个简单的程序来创建视图翻转,例如:
在 Activity 中你必须创建这个方法,用于在视图中添加翻转旋转。
private void applyRotation(View view)
{
final Flip3dAnimation rotation = new Flip3dAnimation(view);
rotation.applyPropertiesInRotation();
view.startAnimation(rotation);
}
为此,您必须复制用于提供翻转旋转的主类。
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;
public class Flip3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private Camera mCamera;
public Flip3dAnimation(View view) {
mFromDegrees = 0;
mToDegrees = 720;
mCenterX = view.getWidth() / 2.0f;
mCenterY = view.getHeight() / 2.0f;
}
@Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
public void applyPropertiesInRotation()
{
this.setDuration(2000);
this.setFillAfter(true);
this.setInterpolator(new AccelerateInterpolator());
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees
+ ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
Log.e("Degree",""+degrees) ;
Log.e("centerX",""+centerX) ;
Log.e("centerY",""+centerY) ;
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
【讨论】:
本教程或 om252345 的链接不会产生可信的 3D 翻转。 y 轴上的简单旋转不是 iOS 中所做的。还需要缩放效果来创造良好的翻转感觉。为此,请查看this example。 还有视频here。
【讨论】:
在不使用资源动画的情况下翻转图像的一种更好的解决方案如下:-
ObjectAnimator animation = ObjectAnimator.ofFloat(YOUR_IMAGEVIEW, "rotationY", 0.0f, 360f); // HERE 360 IS THE ANGLE OF ROTATE, YOU CAN USE 90, 180 IN PLACE OF IT, ACCORDING TO YOURS REQUIREMENT
animation.setDuration(500); // HERE 500 IS THE DURATION OF THE ANIMATION, YOU CAN INCREASE OR DECREASE ACCORDING TO YOURS REQUIREMENT
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.start();
【讨论】:
最简单的方法是使用ViewPropertyAnimator
mImageView.animate().rotationY(360f);
使用流畅的界面,您可以构建更复杂、更精彩的动画。 例如。您只需调用 withLayer() 方法(API 16)即可启用硬件加速。更多here
我实施自己的解决方案仅用于研究。它包括:取消、加速、支持 API >= 15 并且基于Property Animation。 整个动画包括4个部分,每边2个。 每个 objectAnimator 都有一个侦听器,它定义当前动画索引并在 onAnimationStart 中表示图像,在 onAnimationCancel 中表示当前播放时间值。 好像
mQuarterAnim1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mQuarterCurrentAnimStartIndex = QUARTER_ANIM_INDEX_1;
mImageView.setImageResource(mResIdFrontCard);
}
@Override
public void onAnimationCancel(Animator animation) {
mQuarterCurrentAnimPlayTime = ((ObjectAnimator) animation).getCurrentPlayTime();
}
});
对于开始集合调用
mAnimatorSet.play(mQuarterAnim1).before(mQuarterAnim2)
如果取消了 AnimatorSet,我们可以根据当前索引动画和当前播放时间值计算 delta 并运行反向动画。
long degreeDelta = mQuarterCurrentAnimPlayTime * QUARTER_ROTATE / QUARTER_ANIM_DURATION;
if (mQuarterCurrentAnimStartIndex == QUARTER_ANIM_INDEX_1) {
mQuarterAnim4.setFloatValues(degreeDelta, QUARTER_FROM_1);
mQuarterAnim4.setDuration(mQuarterCurrentAnimPlayTime);
mAnimatorSet.play(mQuarterAnim4);
}
完整代码sn-p你可以找到here
【讨论】:
只需将要为其设置动画的视图代替 viewToFlip。
ObjectAnimator flip = ObjectAnimator.ofFloat(viewToFlip, "rotationY", 0f, 360f); // or rotationX
flip.setDuration(2000); // 2 seconds
flip.start();
【讨论】:
添加到 A. Steenbergen 的出色答案。翻转相同视图时(例如更新TextView),我删除了构造函数中的View.Visibility 更改,以保持过渡更平滑。
public FlipListener(final View front, final View back) {
this.mFrontView = front;
this.mBackView = back;
}
【讨论】: