Advertisement

android 翻页动态效果,基于Android实现3D翻页效果

阅读量:

最近开发了一个较为简单的3D效果翻页特效。让我来分享一下我的开发思路。值得注意的是,并不是通过两个Activity之间的跳转来实现的,而是通过同一个activity类内部切换不同的View来完成的效果。具体操作中,在按钮点击事件中使用gone组件取消当前布局,并将目标布局设置为可见状态。在隐藏当前布局的过程中触发 animation 效果,并为该 animation 添加相应的监听逻辑,在 animation 完成之后立即启动下一个 view 的入场动画过程。

下面来看下我的主页面的布局文件:

android:id="@+id/container"

android:layout_width="fill_parent"

android:layout_height="fill_parent" >

android:layout_width="fill_parent"

android:layout_height="fill_parent"

layout="@layout/layout2" />

android:layout_width="fill_parent"

android:layout_height="fill_parent"

layout="@layout/layout1" />

该布局文件通过标签嵌入了另两个布局文件;值得注意的是这些文件是数据展示的核心依据;具体来说下面就是这两个关键的数据展示部分:

layout1:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@drawable/test1"

android:orientation="vertical"

android:id="@+id/container1"

android:id="@+id/bt_towhile"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="白色" />

layout2:

android:id="@+id/container2"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@drawable/test2"

android:orientation="vertical" >

android:id="@+id/bt_toblack"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="黑色" />

为了说明问题,并未放置任何实质性的内容。其中包含两个按钮元素。当我在其中点击一个按钮后会跳转至另一个布局页面。

一旦拥有布局文件后,我们就着手实施功能模块.我们的思路是,当按下按钮时启动第一个动画,待其结束后立即启动第二个动画,并依次隐藏和展示layout1和layout2.

下面是我写的一个动画工具类源码:

package com.test.view;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.Animation;

import android.view.animation.DecelerateInterpolator;

public class RotateAnimationUtil {

private ViewGroup context;

private View[] views;

public RotateAnimationUtil(ViewGroup context, View... views) {

super();

this.context = context;

this.views = views;

}

/**

  • 应用自定义的Rotate3DAnimation动画

  • @param flag

  • 当前控件的顺序坐标

  • @param startDegress

  • 开始的角度

  • @param endDegress

  • 结束的角度

*/

public void applyRotateAnimation(int flag, float startDegress,

float endDegress) {

final float centerX = context.getWidth() / 2.0f;

final float centerY = context.getHeight() / 2.0f;

Rotate3DAnimation rotate = new Rotate3DAnimation(startDegress,

endDegress, centerX, centerY, 310.0f, true);

rotate.setDuration(1000);

rotate.setFillAfter(false);

rotate.setInterpolator(new DecelerateInterpolator());

rotate.setAnimationListener(new DisplayNextView(flag));

context.startAnimation(rotate);

}

private static final class DisplayNextView extends Animation.AnimationListener {

private final int mFlag;

private DisplayNextView(int flag) {

mFlag = flag;

}

public void onAnimationStart(Animation animation) {

}

// 动画结束

public void onAnimationEnd(Animation animation) {

context.post(new SwapViews(mFlag));

}

public void onAnimationRepeat(Animation animation) {

}

}

/**

  • 新开一个线程动画结束后再开始一次动画效果实现翻屏特效

  • @author yangzhiqiang

*/

private final class SwapViews implements Runnable {

private final int mFlag;

public SwapViews(int mFlag) {

this.mFlag = mFlag;

}

public void run() {

final float centerX = context.getWidth() / 2.0f;

final float centerY = context.getHeight() / 2.0f;

Rotate3DAnimation rotation;

if (mFlag > -1) {

views[0].setVisibility(View.GONE);

views[1].setVisibility(View.VISIBLE);

views[1].requestFocus();

rotation = new Rotate3DAnimation(270, 360, centerX, centerY,

310.0f, false);

} else {

views[1].setVisibility(View.GONE);

views[0].setVisibility(View.VISIBLE);

views[0].requestFocus();

rotation = new Rotate3DAnimation(90, 0, centerX, centerY,

310.0f, false);

}

rotation.setDuration(1000);

rotation.setFillAfter(false);

rotation.setInterpolator(new DecelerateInterpolator());

// 开始动画

context.startAnimation(rotation);

}

}

}

解释一下这个类的构造方法:

public RotateAnimationUtil(ViewGroup context, View... views) {

super();

this.context = context;

this.views = views;

}

涉及两个参数。其中该布局即是我们主布局页面的FrameLayout。第二个参数则是用于切换动画效果的两个子布局。这里采用的是一个可变长度的参数仅为便利起见。

public void applyRotateAnimation(int flag, float startDegress, float endDegress)此方法的第一个参数表示当前动画起始自哪一个布局的变化。为了计算动画旋转的角度变化,我们必须知道启动旋转的那个布局。

下面是我自定义动画的源码:

package com.test.view;

import android.graphics.Camera;

import android.graphics.Matrix;

import android.view.animation.Animation;

import android.view.animation.Transformation;

public class Rotate3DAnimation extends Animation {

private final float mFormDegress;

private final float mToDegress;

private final float mCenterX;

private final float mCenterY;

/**

  • 控制z轴的一个常量值,主要是控制动画的升降距离

*/

private final float mDepthz;

/**

  • 控制z轴是像上移动还是向下移动,从而实现升降效果

*/

private final boolean mReverse;

private Camera mCamera;

public Rotate3DAnimation(float startAngle, float endAngle, float centerXCoordinate, ...)

float centerY, float depthz, boolean reverse) {

super();

this.mFormDegress = formDegress;

this.mToDegress = toDegress;

this.mCenterX = centerX;

this.mCenterY = centerY;

this.mDepthz = depthz;

this.mReverse = reverse;

}

@Override

public void initialize(int width, int height, int parentWidth,

int parentHeight) {

super.initialize(width, height, parentWidth, parentHeight);

mCamera = new Camera();

}

/**

interpolatedTime 的取值范围是0到1之间,在每次动画开始运行时(即 animation starts),系统会在每个动画帧期间不断执行 applyTransformation 方法。

  • 并改变interpolatedTime的值

*/

@Override

protected void transform(float interpolatedTime, Transformation transformation) {

final float formDegress = mFormDegress;

// 通过差点值计算出转变的角度

float degress = formDegress

+ ((mToDegress - formDegress) * interpolatedTime);

final float centerX = mCenterX;

final float centerY = mCenterY;

final Camera camera = mCamera;

// 得到当前矩阵

Matrix matrix = t.getMatrix();

// 报错当前屏幕的状态

camera.save();

// 判断是降还是升

if (mReverse) {

// 正向改变Z轴角度

camera.translate(0.0f, 0.0f, mDepthz * interpolatedTime);

} else {

// 反向改变Z轴角度

camera.translate(0.0f, 0.0f, mDepthz * (1.0f - interpolatedTime));

}

// 旋转Y轴角度

camera.rotateY(degress);

// 把当前改变后的矩阵信息复制给Transformation的Matrix

camera.getMatrix(matrix);

// 根据改变后的矩阵信息从新恢复屏幕

camera.restore();

// 让动画在屏幕中间运行

matrix.preTranslate(-centerX, -centerY);

matrix.postTranslate(centerX, centerY);

}

}

如果你不需要沉降效果那么你把下面的代码删除掉即可:

if (mReverse) {

// 正向改变Z轴角度

camera.translate(0.0f, 0.0f, mDepthz * interpolatedTime);

} else {

// 反向改变Z轴角度

camera.translate(0.0f, 0.0f, mDepthz * (1.0f - interpolatedTime));

}

好了核心代码已经上完,下面是主界面代码:

package com.test.rotateanimation;

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.view.View;

import android.view.ViewGroup;

import android.widget.Button;

import android.widget.FrameLayout;

import android.widget.LinearLayout;

import com.test.view.RotateAnimationUtil;

public class MainActivity extends Activity {

private FrameLayout container;

private LinearLayout container1;

private LinearLayout container2;

private RotateAnimationUtil rotateAnimationUtil;

private Button bt_towhile;

private Button bt_toblack;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

bt_towhile.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

rotateAnimationUtil.applyRotateAnimation(1, 0, 90);

}

});

bt_toblack.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

rotateAnimationUtil.applyRotateAnimation(-1, 0, -90);

}

});

// 设置当前View控件的缓存

container

.setPersistentDrawingCache(ViewGroup.PERSISTENT_ANIMATION_CACHE);

}

private void initView() {

container = (FrameLayout) findViewById(R.id.container);

bt_toblack = (Button) findViewById(R.id.bt_toblack);

bt_towhile = (Button) findViewById(R.id.bt_towhile);

container1 = (LinearLayout) findViewById(R.id.container1);

container2 = (LinearLayout) findViewById(R.id.container2);

rotateAnimationUtil = new RotateAnimationUtil(container, container1,

container2);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.activity_main, menu);

return true;

}

}

下面是运行效果,剪切效果不好,呵呵.

6477cd173399eef81fa02e31d2272221.png
a7c99358e2eb25bb202154b466ebc1a7.png
faef97e18504597683bbb1e8642caeb0.png
7e9f14e800fd66edee9d63d9cf0623e8.png

以下是本文的主要内容,旨在为大家提供有价值的学习资源,同时我们也在努力为用户提供更多优质内容.

全部评论 (0)

还没有任何评论哟~