这篇文章主要介绍一下如何实现view的3d旋转效果,实现的主要原理就是围绕y轴旋转,同时在z轴方面上有一个深入的缩放。
演示的demo主要有以下几个重点:
1,自定义旋转动画
2,动画做完后,重置imageview
先看一下程序的运行效果:
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);