现在有些比较特殊的需求,就是Dialog弹窗做卡片翻转,为此做了此相关逻辑实现:
思路:注一个xml文件同时布局正反面UI,做”显示隐藏“操作达到相关翻转效果
//以下代码Fragment or Activity页面调用
private var centerX: Int = 0
private var centerY = 0
private val depthZ = 700 //Z轴,可根据具体效果做相应调整
private val duration = 300
private var openAnimation: Rotate3dAnimation? = null
private var closeAnimation: Rotate3dAnimation? = null
private var isOpen = false //是否翻转
/************** 翻转动画 start ***********/
private fun startAnimation() {
//接口回调传递参数
// centerX = container.getWidth() / 2;
// centerY = container.getHeight() / 2;
centerX = 300
centerY = 300
if (openAnimation == null) {
initOpenAnim()
initCloseAnim()
}
//用作判断当前点击事件发生时动画是否正在执行
if (openAnimation?.hasStarted() == true && openAnimation?.hasEnded() != true) {
return
}
if (closeAnimation?.hasStarted() == true && closeAnimation?.hasEnded() != true) {
return
}
//判断动画执行
if (isOpen) {
mBinding.dialog.startAnimation(openAnimation)
} else {
mBinding.dialog.startAnimation(closeAnimation)
}
isOpen = !isOpen
}
/**
* 卡牌文本介绍打开效果:注意旋转角度
*/
private fun initOpenAnim() {
//从0到90度,顺时针旋转视图,此时reverse参数为true,达到90度时动画结束时视图变得不可见,
openAnimation = Rotate3dAnimation(
0f, 90f, centerX.toFloat(), centerY.toFloat(),
depthZ.toFloat(), true
)
openAnimation?.duration = duration.toLong()
openAnimation?.fillAfter = true
openAnimation?.interpolator = AccelerateInterpolator()
openAnimation?.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
mBinding.inJoinOrControl.inJoinOrControlView.visibility = View.GONE //正反面布局
mBinding.inJoined.inJoinedView.visibility = View.VISIBLE //正反面布局
//从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见
val rotateAnimation = Rotate3dAnimation(
270f, 360f,
centerX.toFloat(), centerY.toFloat(), depthZ.toFloat(), false
)
rotateAnimation.duration = duration.toLong()
rotateAnimation.fillAfter = true
rotateAnimation.interpolator = DecelerateInterpolator()
mBinding.dialog.startAnimation(rotateAnimation)
}
})
}
/**
* 卡牌文本介绍关闭效果:旋转角度与打开时逆行即可
*/
private fun initCloseAnim() {
closeAnimation = Rotate3dAnimation(
360f, 270f, centerX.toFloat(), centerY.toFloat(),
depthZ.toFloat(), true
)
closeAnimation?.duration = duration.toLong()
closeAnimation?.fillAfter = true
closeAnimation?.interpolator = AccelerateInterpolator()
closeAnimation?.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
mBinding.inJoinOrControl.inJoinOrControlView.visibility = View.VISIBLE //正反面布局
mBinding.inJoined.inJoinedView.visibility = View.GONE //正反面布局
val rotateAnimation = Rotate3dAnimation(
90f, 0f,
centerX.toFloat(), centerY.toFloat(), depthZ.toFloat(), false
)
rotateAnimation.duration = duration.toLong()
rotateAnimation.fillAfter = true
rotateAnimation.interpolator = DecelerateInterpolator()
mBinding.dialog.startAnimation(rotateAnimation)
}
})
}
/************** 翻转动画 end ***********/
//翻转动画属性
public class Rotate3dAnimation extends Animation {
private float mFromDegrees;
private float mToDegrees;
private float mCenterX;
private float mCenterY;
private float mDepthZ;
private boolean mReverse;
private Camera mCamera;
public Rotate3dAnimation(float fromDegrees, float toDegrees,
float centerX, float centerY, float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;//Z轴移动的距离,这个来影响视觉效果,可以解决flip animation那个给人看似放大的效果
mReverse = reverse;
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
@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();
LogUtils.i("interpolatedTime", interpolatedTime+"");
camera.save();
if (mReverse) {
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
相关xml文件布局
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dialog" android:layout_width="match_parent" android:layout_height="wrap_content"> <!--Join or Control--> <include android:id="@+id/in_join_or_control" layout="@layout/include_viber_park_online" /> <!--Joined--> <include android:id="@+id/in_joined" layout="@layout/include_viber_park_joined" /> </FrameLayout>
以上逻辑实现真实有效,项目中以使用