效果如图(不知道为什么用ddms截图的时候下面会变瘦呢~~):
一、前言:
    Android中并没有提供直接做3D翻转的动画,所以关于3D翻转的动画效果需要我们
在代码中继承android.view.animation.Animation类来实现自定义效果。
二、动画的实现原理:
  
通过重写Animation的 applyTransformation(float interpolatedTime, Transformation t)函数来实现自定义动画效果。

   在绘制动画的过程中会反复的调用applyTransformation函数,每次调用参数interpolatedTime值都会变化,该参数从0 渐 变为1,当该参数为1时表明动画结束。通过参数Transformation 来获取变换的矩阵(matrix),通过改变矩阵就可以实现各种复杂的 效果。

1、动画的运行模式

      中断模式
      独行模式

2Animation类:

    Animation是动画的主要接口,其中主要定义了动画的一些属性比如开始时间,持续时间,是否重复播放等的。

每个动画都重载了父类的applyTransformation方法。这个方法的主要作用是把一些属性组装成一个Transformation类,这个方法会被父类的getTransformation方法调用。另外,每个动画还要个initialize方法,完成初始化工作,动画开始前的一些准备工作。

getTransformationAnimation会根据动画的属性来产生一系列的差值点,然后我们将这些差值点传给applyTransformation,,这个函数将根据这些点来生成不同的Transformation.

其中包括了旋转的开始和结束角度、中心点、是否扭曲和一个Camera,这里我们主要分析applyTransformation函数,其中第一个参数就是通过getTransformation函数传递的差值点,然后我们根据这个差值线性插值算法算出一个中间角度degrees,Camera类是用来实现绕Y轴旋转后透视投影的,因此我们首先通过t.getMatrix()取得当前的矩阵,然后通过camera.translate来对矩阵进行平移变换操作,camera.rotateY进行旋转。就可以实现3D旋转效果了。

3Interpolator

    定义动画执行过程一些加速度减速度,为了我们后面Transformation来服务的。

4Transformation

    Transformation记录了放射矩阵Matrix,动画每触发一次,会对原来的矩阵做一次运算,ViewBitmap与这个矩阵相乘就可以实现相应的操作(旋转、平移、缩放等)。

    Transformation类封装了矩阵和alpha值,它有两个重要成员,一个mMatrix,一个是mAlpha(控制透明度)

三、activity切换翻转效果源码

Transition3dActivity.java(这个文件在api demo里有:http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/animation/Rotate3dAnimation.html

    

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.huashao.Transition3d;

import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.graphics.Camera;
import android.graphics.Matrix;

/**
* An animation that rotates the view on the Y axis between two specified angles.
* This animation also adds a translation on the Z axis (depth) to improve the effect.
*/
public class Rotate3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;

/**
* Creates a new 3D rotation on the Y axis. The rotation is defined by its
* start angle and its end angle. Both angles are in degrees. The rotation
* is performed around a center point on the 2D space, definied by a pair
* of X and Y coordinates, called centerX and centerY. When the animation
* starts, a translation on the Z axis (depth) is performed. The length
* of the translation can be specified, as well as whether the translation
* should be reversed in time.
*
* @param fromDegrees the start angle of the 3D rotation
* @param toDegrees the end angle of the 3D rotation
* @param centerX the X center of the 3D rotation
* @param centerY the Y center of the 3D rotation
* @param reverse true if the translation should be reversed, false otherwise
*/
public Rotate3dAnimation(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);
}
}

ITabHostMenuHandler接口:

    

package com.huashao.Transition3d;

import java.io.Serializable;

public interface ITabHostMenuHandler extends Serializable {

public static final class TabHostSubClazzSimpleName {
public static final String TAG_MODULE1 = "ModuleView1";
public static final String TAG_MODULE2 = "ModuleView2";

}

public void applyRotation(int position, float start, float end);
}

 NewsTabActivity.java(继承自ActivityGroup的类)

    

package com.hhf.Transition3d;


import java.io.Serializable;

import com.huashao.Transition3d.R;

import android.app.ActivityGroup;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class NewsTabActivity extends ActivityGroup implements ITabHostMenuHandler {

private FrameLayout container = null;
private View view;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 隐藏标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 设置视图
setContentView(R.layout.layout);

container = (FrameLayout) findViewById(R.id.container);
container.removeAllViews();
Intent Module1Intent = new Intent(this, ModuleView1.class);
Module1Intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
Bundle Bundle = new Bundle();
Bundle.putSerializable(ITabHostMenuHandler.TabHostSubClazzSimpleName.TAG_MODULE1, this);
Module1Intent.putExtras(Bundle);
view=getLocalActivityManager().startActivity("Module1", Module1Intent).getDecorView();
container.addView(view);

container.setPersistentDrawingCache(ViewGroup.PERSISTENT_ANIMATION_CACHE);
}
public void applyRotation(int position, float start, float end) {
System.out.println("applyRotation start......");
// Find the center of the container
final float centerX = container.getWidth() / 2.0f;
final float centerY = container.getHeight() / 2.0f;

// Create a new 3D rotation with the supplied parameter
// The animation listener is used to trigger the next animation
final Rotate3dAnimation rotation =
new Rotate3dAnimation(start, end, centerX, centerY, 310.0f, true);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());
rotation.setAnimationListener(new DisplayNextView(position));

container.startAnimation(rotation);
System.out.println("applyRotation end .....");
}




/**
* This class listens for the end of the first half of the animation.
* It then posts a new action that effectively swaps the views when the container
* is rotated 90 degrees and thus invisible.
*/
private final class DisplayNextView implements Animation.AnimationListener {
private final int mPosition;

private DisplayNextView(int position) {
mPosition = position;
}

public void onAnimationStart(Animation animation) {
}

public void onAnimationEnd(Animation animation) {
container.post(new SwapViews(mPosition));
}

public void onAnimationRepeat(Animation animation) {
}
}

/**
* This class is responsible for swapping the views and start the second
* half of the animation.
*/
private final class SwapViews implements Runnable {
private final int mPosition;

public SwapViews(int position) {
mPosition = position;
}

public void run() {
final float centerX = container.getWidth() / 2.0f;
final float centerY = container.getHeight() / 2.0f;
Rotate3dAnimation rotation;
System.out.println("SwapViews start +++++++ ");
if (mPosition > -1) {
container.removeAllViews();
Intent Module1Intent = new Intent(NewsTabActivity.this, ModuleView1.class);
Module1Intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle Bundle = new Bundle();
Bundle.putSerializable(ITabHostMenuHandler.TabHostSubClazzSimpleName.TAG_MODULE1, NewsTabActivity.this);
Module1Intent.putExtras(Bundle);
view=getLocalActivityManager().startActivity("Module1", Module1Intent).getDecorView();
container.addView(view);

rotation = new Rotate3dAnimation(90, 180, centerX, centerY, 310.0f, false);
} else {
container.removeAllViews();
Intent Module1Intent = new Intent(NewsTabActivity.this, ModuleView2.class);
Module1Intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
Bundle Bundle = new Bundle();
Bundle.putSerializable(ITabHostMenuHandler.TabHostSubClazzSimpleName.TAG_MODULE2, NewsTabActivity.this);
Module1Intent.putExtras(Bundle);
view=getLocalActivityManager().startActivity("Module2", Module1Intent).getDecorView();
container.addView(view);

rotation = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f, false);
}

rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new DecelerateInterpolator());

container.startAnimation(rotation);
System.out.println("SwapViews end ++++++ ");
}
}
}

两个相互切换的Activity(ModuleView1.java和ModuleView2.java)
ModuleView1.java
    

package com.hhf.Transition3d;
import com.hhf.Transition3d.ITabHostMenuHandler.TabHostSubClazzSimpleName;
import com.huashao.Transition3d.R;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;

public class ModuleView1 extends Activity implements View.OnClickListener {
private ITabHostMenuHandler tabHostMenuHandler;
private ImageView img;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.view1layout);
img=(ImageView) findViewById(R.id.picture);
img.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.d("", "ModuleView1");
tabHostMenuHandler. applyRotation(-1, 180, 90);
}
});
tabHostMenuHandler = (ITabHostMenuHandler) getIntent().getExtras().getSerializable(TabHostSubClazzSimpleName.TAG_MODULE1);
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub

}

}

ModuleView2.java
    

package com.hhf.Transition3d;



import com.hhf.Transition3d.ITabHostMenuHandler.TabHostSubClazzSimpleName;
import com.huashao.Transition3d.R;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ImageView;

public class ModuleView2 extends Activity implements View.OnClickListener {
private ITabHostMenuHandler tabHostMenuHandler;
private ImageView img;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.view2layout);
img=(ImageView) findViewById(R.id.picture);
img.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.d("", "ModuleView1");
tabHostMenuHandler.applyRotation(1, 0, 90);
}
});
tabHostMenuHandler = (ITabHostMenuHandler) getIntent().getExtras().getSerializable(TabHostSubClazzSimpleName.TAG_MODULE2);
ImageView i = (ImageView) findViewById(R.id.img);
i.setOnClickListener(this);
}


@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.img:
Intent in = new Intent(ModuleView2.this,MainActivity.class);
startActivity(in);
break;

default:
break;
}
}


}

从MoudleView2上面按钮跳转的MainActivity(正常继承自Acitivity的activity)
    

package com.hhf.Transition3d;

import com.huashao.Transition3d.R;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

public class MainActivity extends Activity{
private ImageView img;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.view1layout);
img=(ImageView) findViewById(R.id.picture);
img.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Intent in = new Intent(MainActivity.this,NewsTabActivity.class);
startActivity(in);
}
});
}
}

四、Camera的使用

Camera就像一个摄像机,一个物体在原地不动,然后我们带着这个摄像机四处移动,在摄像机里面呈现出来的画面,就会有立体感,就可以从各个角度观看这个物体。

它有旋转、平移的一系列方法,实际上都是在改变一个Matrix对象,一系列操作完毕之后,我们得到这个Matrix,然后画我们的物体,就可以了。

常用的API如下:

  rotateX(float degree) 绕着x轴旋转degree个度数

  rotateY(float degree) 绕着y轴旋转degree个度数

  rotateZ(float degree) 绕着z轴旋转degree个度数

  translate(float x,float y,float z) 平移一段距离

  save()和restore() 作用跟Canvas的一样,保存原状态,操作完之后,恢复到原状态。


 
  

更多相关文章

  1. Android动画之Animation
  2. Android 动画之Tween动画详细讲解
  3. Android 关于 Activity 之间的切换动画
  4. Android 开关机动画修改
  5. android Animation动画效果基础
  6. Android进阶:实现android系统自带查看照片动画效果 类似Gallery手

随机推荐

  1. Android Studio中使用com.android.suppor
  2. Android应用程序启动Binder线程源码分析
  3. Android WebView 用法
  4. 【Android开机启动Activity或者Service方
  5. 定制自己的 Android(安卓)Dialog 信息提
  6. Android常用开源库(模块部分)
  7. 10.Android之测试代码实现步骤
  8. Android客户端通过socket与服务器通信
  9. 离线下载android sdk
  10. Android学习与面试重点目录