欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 3D旋转动画效果实现分解

程序员文章站 2023-11-27 18:42:34
这篇文章主要介绍一下如何实现view的3d旋转效果,实现的主要原理就是围绕y轴旋转,同时在z轴方面上有一个深入的缩放。演示的demo主要有以下几个重点: 1,自定义旋转动画...
这篇文章主要介绍一下如何实现view的3d旋转效果,实现的主要原理就是围绕y轴旋转,同时在z轴方面上有一个深入的缩放。

演示的demo主要有以下几个重点:
1,自定义旋转动画
2,动画做完后,重置imageview
先看一下程序的运行效果:
Android 3D旋转动画效果实现分解 
1,自定义动画类
这里实现了一个rotate3danimation的类,它扩展了animation类,重写applytransformation()方法,提供指定时间的矩阵变换,我们在这个方法里,就可以利用camera类得得到一个围绕y轴旋转的matrix,把这个matrix设置到transformation对象中。 具体的实现代码如下:
复制代码 代码如下:

@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);
}

2,如何使用这个动画类
在activity中,我们有两个大小一样的imageview,它们都放在framelayout中,这样他们位置是重叠的,对最上面的imageview做动画(旋转角度从0到90),当动画做完后,再对后面的imageview做动画(旋转角度从90到180),在这里,要控制相应的imageview隐藏或显示。
动画的listener实现如下:
复制代码 代码如下:

private final class displaynextview implements animation.animationlistener {
public void onanimationstart(animation animation) {
}
public void onanimationend(animation animation) {
mcontainer.post(new swapviews());
}
public void onanimationrepeat(animation animation) {
}
}

动画做完后,执行的代码如下:
复制代码 代码如下:

private final class swapviews implements runnable
{
@override
public void run()
{
mimageview1.setvisibility(view.gone);
mimageview2.setvisibility(view.gone);
mindex++;
if (0 == mindex % 2)
{
mstartanimview = mimageview1;
}
else
{
mstartanimview = mimageview2;
}
mstartanimview.setvisibility(view.visible);
mstartanimview.requestfocus();
rotate3danimation rotation = new rotate3danimation(
-90,
0,
mcenterx,
mcentery, mdepthz, false);
rotation.setduration(mduration);
rotation.setfillafter(true);
rotation.setinterpolator(new decelerateinterpolator());
mstartanimview.startanimation(rotation);
}
}

点击button的事件处理实现:
复制代码 代码如下:

@override
public void onclick(view v)
{
mcenterx = mcontainer.getwidth() / 2;
mcentery = mcontainer.getheight() / 2;
getdepthz();
applyrotation(mstartanimview, 0, 90);
}

applyrotation的实现如下:
复制代码 代码如下:

private void applyrotation(view animview, float startangle, float toangle)
{
float centerx = mcenterx;
float centery = mcentery;
rotate3danimation rotation = new rotate3danimation(
startangle, toangle, centerx, centery, mdepthz, true);
rotation.setduration(mduration);
rotation.setfillafter(true);
rotation.setinterpolator(new accelerateinterpolator());
rotation.setanimationlistener(new displaynextview());
animview.startanimation(rotation);
}

3,完整代码如下
rotate3danimactivity.java
复制代码 代码如下:

public class rotate3danimactivity extends activity
{
imageview mimageview1 = null;
imageview mimageview2 = null;
imageview mstartanimview = null;
view mcontainer = null;
int mduration = 500;
float mcenterx = 0.0f;
float mcentery = 0.0f;
float mdepthz = 0.0f;
int mindex = 0;
@override
public void oncreate(bundle savedinstancestate)
{
super.oncreate(savedinstancestate);
setcontentview(r.layout.rotate_anim);
mimageview1 = (imageview) findviewbyid(r.id.imageview1);
mimageview2 = (imageview) findviewbyid(r.id.imageview2);
mcontainer = findviewbyid(r.id.container);
mstartanimview = mimageview1;
findviewbyid(r.id.button1).setonclicklistener(new view.onclicklistener()
{
@override
public void onclick(view v)
{
mcenterx = mcontainer.getwidth() / 2;
mcentery = mcontainer.getheight() / 2;
getdepthz();
applyrotation(mstartanimview, 0, 90);
}
});
inputmethodmanager imm = (inputmethodmanager)getsystemservice(input_method_service);
imm.hidesoftinputfromwindow(getwindow().getdecorview().getwindowtoken(), inputmethodmanager.hide_not_always);
}
private void getdepthz()
{
edittext edittext = (edittext) findviewbyid(r.id.edit_depthz);
string string = edittext.gettext().tostring();
try
{
mdepthz = (float)integer.parseint(string);
//mdepthz = math.min(mdepthz, 300.0f);
}
catch (exception e)
{
e.printstacktrace();
}
}
private void applyrotation(view animview, float startangle, float toangle)
{
float centerx = mcenterx;
float centery = mcentery;
rotate3danimation rotation = new rotate3danimation(
startangle, toangle, centerx, centery, mdepthz, true);
rotation.setduration(mduration);
rotation.setfillafter(true);
rotation.setinterpolator(new accelerateinterpolator());
rotation.setanimationlistener(new displaynextview());
animview.startanimation(rotation);
}
/**
* 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 {
public void onanimationstart(animation animation) {
}
public void onanimationend(animation animation) {
mcontainer.post(new swapviews());
}
public void onanimationrepeat(animation animation) {
}
}
private final class swapviews implements runnable
{
@override
public void run()
{
mimageview1.setvisibility(view.gone);
mimageview2.setvisibility(view.gone);
mindex++;
if (0 == mindex % 2)
{
mstartanimview = mimageview1;
}
else
{
mstartanimview = mimageview2;
}
mstartanimview.setvisibility(view.visible);
mstartanimview.requestfocus();
rotate3danimation rotation = new rotate3danimation(
-90,
0,
mcenterx,
mcentery, mdepthz, false);
rotation.setduration(mduration);
rotation.setfillafter(true);
rotation.setinterpolator(new decelerateinterpolator());
mstartanimview.startanimation(rotation);
}
}
}

rotate_anim.xml
复制代码 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="do 3d animation" />
<textview
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginleft="20px"
android:text="input depth on z axis. [0, 300]"
/>
<edittext
android:id="@+id/edit_depthz"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="0"/>
<framelayout
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<imageview
android:id="@+id/imageview1"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_margin="20dp"
android:src="@drawable/f" />
<imageview
android:id="@+id/imageview2"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_margin="20dp"
android:src="@drawable/s"
android:visibility="gone"/>
</framelayout>
</linearlayout>

rotate3danimation.java
复制代码 代码如下:

package com.nj1s.lib.anim;
import android.graphics.camera;
import android.graphics.matrix;
import android.view.animation.animation;
import android.view.animation.transformation;
/**
* 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);
}
}

各位,请想一想,为实现applytransformation方法时,最后的为什么要有这两句话:
matrix.pretranslate(-centerx, -centery);
matrix.posttranslate(centerx, centery);