基于Android实现3D翻页效果

 更新时间:2022年05月10日 08:17:30   作者:楊先生  
这篇文章主要为大家详细介绍了基于Android实现3D翻页效果的具体代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

最近做了一个简单的3D效果翻页特效,先说说我的思路吧,首先我这个翻页效果并不是两个Activity之间的跳转,而是在同一个activity类切换不同的view而已。我现在的做法是单击一个button然后Gone当前的布局,然后把需要呈现的布局visible,在隐藏当前布局的时候启动动画,然后给动画添加监听,在动画结束时开始另外一个view的入场动画就行了。
下面来看下我的主页面的布局文件:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/container" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" > 
 
 <include 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 layout="@layout/layout2" /> 
 
 <include 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 layout="@layout/layout1" /> 
 
</FrameLayout> 

我这个布局文件使用<include>标签包含了另外2个布局文件,这些布局文件才是呈现数据的,下面是另外2个布局文件:

layout1:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="@drawable/test1" 
 android:orientation="vertical" 
 android:id="@+id/container1" 
 > 
 
 <Button 
 android:id="@+id/bt_towhile" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_gravity="center" 
 android:text="白色" /> 
 
</LinearLayout> 

layout2:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/container2" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="@drawable/test2" 
 android:orientation="vertical" > 
 
 <Button 
 android:id="@+id/bt_toblack" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_gravity="center" 
 android:text="黑色" /> 
 
</LinearLayout> 

我这里只是举个例子并没有放什么实际的类容,只是放了2个button,当我点击其中一个跳转到另外一个layout。

有了布局文件那我们就开始要实现功能了,我们的想法是点击按钮的时候开始一个动画等动画结束时再开启另外一个动画并隐藏和展示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 final class DisplayNextView implements 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; 
 } 

有2个参数,第一个参数就是我们的主布局页面的FrameLayout,第2个参数就是我们要进行动画切换的2个子layout,我这使用的是一个可变长参数只是为了方便而已。

public void applyRotateAnimation(int flag, float startDegress,float endDegress)方法第一个参数是标记当前是第是从哪个个layout跳转,因外我们必须知道当前开始跳转的layout才能推算角度。
下面是我自定义动画的源码:

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 formDegress, float toDegress, float centerX, 
  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之间当每次,当动画启动后会系统会不停的调用applyTransformation方法, 
 * 并改变interpolatedTime的值 
 */ 
 @Override 
 protected void applyTransformation(float interpolatedTime, Transformation t) { 
 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; 
 } 
 
} 

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

 源码下载:http://xiazai.jb51.net/201606/yuanma/RotateAnimation(jb51.net).rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Jetpack Compose之选择器使用实例讲解

    Jetpack Compose之选择器使用实例讲解

    这篇文章主要介绍了Jetpack Compose之选择器使用,选择器主要是指Checkbox复选框,单选开关Switch,滑杆组件Slider等用于提供给用户选择一些值和程序交互的组件,比如像复选框Checkbox,可以让用户选择一个或者多个选项
    2023-04-04
  • Android实现发送短信功能实例详解

    Android实现发送短信功能实例详解

    这篇文章主要介绍了Android实现发送短信功能的方法,结合实例形式较为详细的分析了Android实现发送短信的原理、步骤与相关实现技巧,需要的朋友可以参考下
    2016-02-02
  • Android实现自制和播放录音程序

    Android实现自制和播放录音程序

    这篇文章主要为大家详细介绍了Android实现自制和播放录音程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • Android5.0+ CollapsingToolbarLayout使用详解

    Android5.0+ CollapsingToolbarLayout使用详解

    这篇文章主要为大家详细介绍了Android5.0+ CollapsingToolbarLayout使用,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • Android 避免APP启动闪黑屏的解决办法(Theme和Style)

    Android 避免APP启动闪黑屏的解决办法(Theme和Style)

    闪黑屏的原因主要是我们启动Activity的时候,需要跑完onCreate和onResume才会显示界面
    2013-07-07
  • Android选择与上传图片之PictureSelector教程

    Android选择与上传图片之PictureSelector教程

    这篇文章主要介绍了在Android中对于图片的选择与上传方法,本文介绍了PictureSelector的相关使用教程,学习Android的同学进来看看吧
    2021-08-08
  • Android实现仪表盘控件开发

    Android实现仪表盘控件开发

    这篇文章主要为大家详细介绍了Android实现仪表盘控件开发,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • Android自定义控件实现底部菜单(下)

    Android自定义控件实现底部菜单(下)

    这篇文章主要为大家详细介绍了Android自定义控件实现底部菜单的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Android进阶事件分发机制解决事件冲突

    Android进阶事件分发机制解决事件冲突

    这篇文章主要为大家介绍了Android进阶事件分发机制解决事件冲突过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Android使用fragment实现左侧导航

    Android使用fragment实现左侧导航

    这篇文章主要为大家详细介绍了Android使用fragment实现左侧导航,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02

最新评论