您的位置:首页 > 移动开发 > Android开发

android实现3D旋转效果

2014-08-21 16:27 579 查看
最近的项目中要用到3D旋转,搞了两天终于弄出来了,总结一下以供以后重用。

一、知识点介绍

3D旋转效果主要是借助了自定义Animation动画实现。通过继承Animation类,重写applyTransformation (float
interpolatedTime, Transformation t)方法,在方法中使用Camera和Matrix实现变化。

1、applyTransformation (float
interpolatedTime, Transformation t)方法


参数interpolatedTime表示执行进度(取值为0-1,1的时候动画结束),t为动画变化的载体。

下面具体介绍下这两个参数:

1)、interpolatedTime是Interpolator计算的结果。Interpolator是一个接口,主要用来对动画的播放的时间进度进行控制,有如下几种播放效果:

LinearInterpolator:匀速播放,为默认效果;
AccelerateInterpolator:加速播放;有一个参数factor,为加速因子,值越大加速效果越明显。
DecelerateInterpolator:减速播放;
AccelerateDecelerateInterpolator:先加速后减速播放,即中间播放得最快;
CycleInterpolator:循环播放;
可以通过 animation.setInterpolator(new
AccelerateInterpolator());来设置animation的播放进度。
2)、Transformation
t是动画变化的载体。

动画实际上是每一帧画面的组合,每一帧产生不同的变换,进而产生动画效果。Transformation
就是每一帧动画变化的载体。主要有两个属性:Alpha和Matrix。可以通过t.getMatrix()、t.getAlpha()来获取这两个属性。

2、initialize (int
width, int height, int parentWidth, int parentHeight)函数。


一般也会重写initialize()函数,这是一个回调函数告诉Animation目标View的大小参数,在这里可以初始化一些相关的参数,例如设置动画持续时间、设置Interpolator、设置动画的参考点等。

3、Camera类

Camera类,在android API 中有两个;一个是相机方面的(android.hardware.Camera),一个是图形方面的(android.graphics.Camera)。显然在这里我们用到的是图形方面的类;Camera用来计算3D转换、生成矩阵,然后应用在画布上。它的构造方法只有一个不带参数的Camera(),用于实例化一个带有空的转换的Camera。
其主要方法如下:

translate(float x,float y,float z):平移,它和canvas.translate(dx,
dy)的不同之处就在于它可以相对屏幕前后平移(即在z轴平移)。

rotateX(float deg):以X轴为轴心旋转deg角度;

rotateY(float deg):以Y轴为轴心旋转deg角度;

rotateZ(float
deg):以Z轴为轴心旋转deg角度;

save():保存变换状态

restore():恢复变换状态

4、Matrix类

用于处理三维的矩阵坐标变换,也常用于图片的处理。Matrix提供了translate(平移)、rotate(旋转)、scale(缩放)、skew(倾斜)四种操作,这四种操作的内部实现过程都是通过matrix.setValues(…)来设置矩阵的值来达到变换图片的效果。Matrix的每种操作都有set、pre、post三种操作,set是清空队列再添加,pre是在队列最前面插入,post是在队列最后面插入。除了translate,其他三种操作都可以指定中心点。

二、源代码

自定义Animation

package com.dream.rotatedemo;

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

public class MyAnimation extends Animation {

private Camera camera;

private float fromDegree;
private float toDegree;
private float centerX;
private float centerY;
private float depthZ;
private boolean showReverse;
private boolean encircleX;

public MyAnimation(float fromDegree, float toDegree,float depthZ,boolean showReverse,boolean encircleX) {
super();
this.fromDegree = fromDegree;
this.toDegree = toDegree;
this.depthZ=depthZ;
this.showReverse=showReverse;
this.encircleX=encircleX;
}

@Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
// TODO Auto-generated method stub
super.initialize(width, height, parentWidth, parentHeight);

camera=new Camera();

centerX=width/2;
centerY=height>>1;
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {

float degree=fromDegree+(toDegree-fromDegree)*interpolatedTime;

Matrix m=t.getMatrix();

camera.save();
if(showReverse)
camera.translate(0, 0, depthZ*(1-interpolatedTime));
else
camera.translate(0, 0, depthZ*interpolatedTime);

if(encircleX==true)
camera.rotateX(degree);
else
camera.rotateY(degree);
camera.getMatrix(m);
camera.restore();

//在旋转之前执行
m.preTranslate(-centerX, -centerY);
//在旋转完成之后执行
m.postTranslate(centerX, centerY);

}

}


MainActivity

package com.dream.rotatedemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends Activity {

//private ImageView iv;
private TextView tv;
private int count;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

tv=(TextView)findViewById(R.id.tv);
tv.setBackgroundResource(R.drawable.olivecard_a1);
//iv=(ImageView)findViewById(R.id.iv);
//iv.setImageResource(R.drawable.olivecard_a1);

tv.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
MyAnimation animation=new MyAnimation(0f, 90f,300f,false,true);
animation.setDuration(500);
animation.setFillAfter(true);
animation.setInterpolator(new AccelerateInterpolator());
animation.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationEnd(Animation animation) {
changeImg();
tv.post(new SwapView());
}

});
tv.startAnimation(animation);

}
});
}

class SwapView implements Runnable{
@Override
public void run() {
showReverse();
}
}

private void showReverse() {
MyAnimation anim=new MyAnimation(0f,0f, 300f, true,true);
anim.setDuration(500);
anim.setInterpolator(new AccelerateInterpolator());
anim.setFillAfter(true);
anim.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationEnd(Animation animation) {

}
});

tv.startAnimation(anim);
}

private void changeImg() {
//		if((++count)%2==0){
//			iv.setImageResource(R.drawable.olivecard_a1);
//		}else{
//			iv.setImageResource(R.drawable.a2);
//		}

if((++count)%2==0){
tv.setBackgroundResource(R.drawable.olivecard_a1);
}else{
tv.setBackgroundResource(R.drawable.a2);
}

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

return super.onOptionsItemSelected(item);
}

}


值得注意的是matrix的preTranslate(-centerX, -centerY)方法及postTranslate(centerX,centerY)方法
由于操作的中心点默认为(0,0)所以为了使控件的中心点和操作的中心点对齐,要设置preTranslate(-centerX, -centerY),postTranslate(-centerX, -centerY),其中centerX和centerY为控件的中心点;这样看起来的效果就是以控件的中心为中心点进行操作的。

刚开始的时候,我直接是将图片旋转180度,但是发现那样出来的图片会是反的;所以后来分两步旋转来实现效果;
另记录一个小知识:
View.Post(new Runnable)方法:run()里面的内容会运行在主线程;参考资料:/article/4886527.html

三、参考资料

Android 自定义Animation动画
http://longshuai2007.blog.163.com/blog/static/1420944142011719103059746/

Android Camera 3D效果 http://www.2cto.com/kf/201404/293250.html

初探android的Camera和Matrix /article/7730657.html

android.graphics.Camera实现图像的旋转、缩放
http://www.open-open.com/lib/view/open1323654024781.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: