这个动画效果是把Activity当做一张纸,正反面都有内容,且当点击正反面的任何一个翻转按钮,Activity都会以屏幕中心为翻转中心点(Z轴的翻转中心点可以自由设定),进行旋转。
这个动画效果的思路是这样的,首先两个界面的布局都在同一个Layout文件中,因为这里只有一个Activity,所以两个界面的布局在同一个layout文件中就要有所设计。
在这里,我使用的是FrameLayout作为父容器,包裹着两个RelativeLayout子容器。当然其他布局也可以,只是在初始化时候必须先设置不可见的一面的布局android:visibility=“gone”
布局文件具体代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/relative_layout_two"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="#50616d">
<TextView
android:id="@+id/tv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="布局2"
android:textColor="#789456"
android:layout_centerInParent="true"
android:textSize="30sp"
android:visibility="gone"/>
<Button
android:id="@+id/rotate_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="翻转"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"/>
RelativeLayout>
<RelativeLayout
android:id="@+id/relative_layout_one"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="#0aa344">
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="布局1"
android:textSize="30sp"
android:textColor="#123456"
android:visibility="visible"
android:layout_centerInParent="true"/>
<Button
android:id="@+id/rotate_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="翻转"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"/>
RelativeLayout>
FrameLayout>
LinearLayout>
注意,在两个RelativeLayout中必须添加android:focusable=”true”
android:focusableInTouchMode=”true”这两个属性来隔离两个界面的监听事件,使得当前显示的一面监听有效,另一个不显示的页面的监听无效,否则点击事件会乱套。
接下来就是翻转效果的设计,首先是确定翻转中心点的位置,通过传入X,Y,Z三个轴的中心点来确定。然后使用Camera根据传入的翻转度来进行翻转,翻转的类Rotate3D代码如下:
/**
* 实现3D旋转动画核心类
* Created by PawN on 2015/6/12.
*/
public class Rotate3D extends Animation{
// 开始角度
private final float mFromDegrees;
// 结束角度
private final float mToDegrees;
// X轴中心点
private final float mCenterX;
// Y轴中心点
private final float mCenterY;
// Z轴中心点
private final float mDepthZ;
//是否需要扭曲
private final boolean mReverse;
//摄像头
private Camera mCamera;
public Rotate3D(float fromDegrees, float toDegrees,
float centerX,float centerY,
float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;
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();//取得当前矩阵
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);
}
}
接下来就是在TestRotateActivity中的使用了,整个翻转过程分为两个阶段操作,第一阶段是从当前页面翻转到整个Activity垂直于手机屏幕(到这个时刻,正反两面都是不可见的)。第二阶段是从当前的整个Activity垂直于手机屏幕(到这个时刻,正反两面都是不可见的)状态翻转到第二个页面显示在手机屏幕上。具体流程如下图所示:
TestRotateActivity的具体代码如下:
public class TestRotateActivity extends Activity{
//布局1
private TextView tvOne;
private Button btnRotateNext;
//布局2
private TextView tvTwo;
private Button btnRotateBack;
//页面翻转容器FrameLayout
private FrameLayout flContainer;
//布局1界面RelativeLayout
private RelativeLayout relativeLayout1;
//布局2界面RelativeLayout
private RelativeLayout relativeLayout2;
//初始化界面索引(1位布局1,2位布局2)
private int index = 1;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rotate);
initView();
registerClickListener();
}
private void initView(){
tvOne = (TextView)findViewById(R.id.tv_one);
tvTwo = (TextView)findViewById(R.id.tv_two);
flContainer =
(FrameLayout)findViewById(R.id.frame_layout);
relativeLayout1 = (RelativeLayout)findViewById(R.id.relative_layout_one);
relativeLayout2 = (RelativeLayout)findViewById(R.id.relative_layout_two);
btnRotateNext = (Button) findViewById(R.id.rotate_next);
btnRotateBack = (Button)findViewById(R.id.rotate_back);
}
private void registerClickListener(){
tvOne.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(TestRotateActivity.this,"one",Toast.LENGTH_SHORT).show();;
}
});
tvTwo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(TestRotateActivity.this,"two",Toast.LENGTH_SHORT).show();;
}
});
btnRotateNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(index==1){
//第一阶段翻转
applyRotation(1,0,90);
index =0;
}else{
//第一阶段翻转
applyRotation(0,0,-90);
index = 1;
}
}
});
btnRotateBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(index==1){
//第一阶段翻转
applyRotation(1,0,90);
index =0;
}else{
//第一阶段翻转
applyRotation(0,0,-90);
index = 1;
}
}
});
}
/**
* 执行翻转第一阶段翻转动画
* @param tag view索引
* @param start 起始角度
* @param end 结束角度
*/
private void applyRotation(int tag, float start, float end) {
// 得到中心点(以中心翻转)
//X轴中心点
final float centerX = flContainer.getWidth() / 2.0f;
//Y轴中心点
final float centerY = flContainer.getHeight() / 2.0f;
//Z轴中心点
final float depthZ = 500.0f;
// 根据参数创建一个新的三维动画,并且监听触发下一个动画
final Rotate3D rotation = new Rotate3D(start, end, centerX, centerY,depthZ, true);
rotation.setDuration(300);//设置动画持续时间
rotation.setInterpolator(new AccelerateInterpolator());//设置动画变化速度
rotation.setAnimationListener(new DisplayNextView(tag));//设置第一阶段动画监听器
flContainer.startAnimation(rotation);
}
/**
* 第一阶段动画监听器
*
*/
private final class DisplayNextView implements Animation.AnimationListener {
private final int tag;
private DisplayNextView(int tag) {
this.tag = tag;
}
public void onAnimationStart(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
//第一阶段动画结束时,也就是整个Activity垂直于手机屏幕,
//执行第二阶段动画
flContainer.post(new SwapViews(tag));
//调整两个界面各自的visibility
adjustVisiable();
}
public void onAnimationRepeat(Animation animation) {
}
}
/**
* 执行翻转第二个阶段动画
*
*/
private final class SwapViews implements Runnable {
private final int tag;
public SwapViews(int position) {
tag = position;
}
public void run() {
if (tag == 0) {
//首页页面以90~0度翻转
showView(relativeLayout1, relativeLayout2, 90, 0);
} else if (tag == 1) {
//音乐页面以-90~0度翻转
showView(relativeLayout2, relativeLayout1, -90, 0);
}
}
}
/**
* 显示第二个视图动画
* @param showView 要显示的视图
* @param hiddenView 要隐藏的视图
* @param startDegree 开始角度
* @param endDegree 目标角度
*/
private void showView(RelativeLayout showView, RelativeLayout hiddenView, int startDegree, int endDegree) {
//同样以中心点进行翻转
float centerX = showView.getWidth() / 2.0f;
float centerY = showView.getHeight() / 2.0f;
float centerZ = 500.0f;
if (centerX == 0 || centerY == 0) {
//调用该方法getMeasuredWidth(),必须先执行measure()方法,否则会出异常。
showView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
//获取该view在父容器里面占的大小
centerX = showView.getMeasuredWidth() / 2.0f;
centerY = showView.getMeasuredHeight() / 2.0f;
}
// Log.e("centerX",centerX + "");
// Log.e("centerY",centerY + "");
hiddenView.setVisibility(View.GONE);
showView.setVisibility(View.VISIBLE);
Rotate3D rotation = new Rotate3D(startDegree, endDegree, centerX, centerY, centerZ, false);
rotation.setDuration(300);//设置动画持续时间
rotation.setInterpolator(new DecelerateInterpolator());//设置动画变化速度
flContainer.startAnimation(rotation);
}
/**
* 两个布局的visibility调节
*/
private void adjustVisiable(){
if(tvOne.getVisibility() == View.VISIBLE){
tvOne.setVisibility(View.GONE);
}else {
tvOne.setVisibility(View.VISIBLE);
}
if(tvTwo.getVisibility() == View.VISIBLE){
tvTwo.setVisibility(View.GONE);
}else {
tvTwo.setVisibility(View.VISIBLE);
}
}
}
这样就可以实现本章的Activity翻转动画效果了~有哪里不妥的地方欢迎大家指正~