当前位置: 移动技术网 > IT编程>移动开发>Android > Android利用Camera实现中轴3D卡牌翻转效果

Android利用Camera实现中轴3D卡牌翻转效果

2019年07月24日  | 移动技术网IT编程  | 我要评论

趣向俱乐部,兽性诱惑2,特工迷影电视剧全集

在android系统api中,有两个camera类:

  • android.graphics.camera
  • android.hardware.camera

第二个应用于手机硬件中的相机相关的操作,本文讲述的是利用第一个camera类实现中轴3d转换的卡牌翻转效果,开始之前,先看一下android系统中的坐标系:

对应于三维坐标系中的三个方向,camera提供了三种旋转方法:

  • rotatex()
  • rotatey()
  • rotatex()

调用这三种方法,传入旋转角度参数,即可实现视图沿着坐标轴旋转的功能。本文的中轴3d旋转效果就是让视图沿着y轴旋转的。

系统api demos中已经为我们提供了一个非常好用的3d旋转动画的工具类:
rotate3danimation.java:

package com.feng.androidtest;

import android.graphics.camera;
import android.graphics.matrix;
import android.util.log;
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();

  log.i("interpolatedtime", interpolatedtime+"");
  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);
 }
}

可以看出, rotate3danimation 总共做了两件事:在构造函数中赋值了旋转动画所需要的参数,以及重写(override)父类animation中的applytransformation()方法,下面分类阐述一下:

  • fromdegrees与todegrees
  • 视图旋转的开始角度和结束角度,当todegree处于90倍数时,视图将变得不可见。
  • centerx与centery
  • 视图旋转的中心点。
  • depthz
  • z轴移动基数,用于计算camera在z轴移动距离
  • reverse
  • boolean类型,控制z轴移动方向,达到视觉远近移动导致的视图放大缩小效果。
  • applytransformation()
  • 根据动画播放的时间 interpolatedtime (动画start到end的过程,interpolatedtime从0.0变化到1.0),让camera在z轴方向上进行相应距离的移动,实现视觉上远近移动的效果。然后调用 rotatex()方法,让视图围绕y轴进行旋转,产生3d立体旋转效果。最后再通过matrix来确定旋转的中心点的位置。

activity_main.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:background="@android:color/white" >

 <button
  android:id="@+id/btn_open"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_margin="16dp"
  android:onclick="onclickview"
  android:text="打开"
  android:textcolor="@android:color/black"
  android:textsize="16sp" />

 <relativelayout
  android:id="@+id/rl_content"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_below="@id/btn_open"
  android:layout_margintop="16dp" 
  android:background="@android:color/black">

  <imageview
   android:id="@+id/iv_logo"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:contentdescription="@null"
   android:src="@drawable/ic_qrcode" 
   android:scaletype="centerinside"/>

  <textview
   android:id="@+id/tv_desc"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:padding="16dp"
   android:text="移动技术网。"
   android:textcolor="@android:color/white"
   android:textsize="18sp" 
   android:visibility="gone"/>
 </relativelayout>

</relativelayout>

布局中配置了卡牌正面的图片控件,卡牌背面的文本控件,以及他们的parent容器,也就是本文中的旋转动画的执行对象。

mainactivity.java文件:

package com.feng.androidtest;

import android.app.activity;
import android.os.bundle;
import android.view.view;
import android.view.animation.accelerateinterpolator;
import android.view.animation.animation;
import android.view.animation.animation.animationlistener;
import android.view.animation.decelerateinterpolator;
import android.widget.button;
import android.widget.imageview;
import android.widget.relativelayout;
import android.widget.textview;

import com.example.androidtest.r;

public class mainactivity extends activity {

 private relativelayout mcontentrl;
 private imageview mlogoiv;
 private textview mdesctv;
 private button mopenbtn;

 private int centerx;
 private int centery;
 private int depthz = 400;
 private int duration = 600;
 private rotate3danimation openanimation;
 private rotate3danimation closeanimation;

 private boolean isopen = false;

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);

  mcontentrl = (relativelayout) findviewbyid(r.id.rl_content);
  mlogoiv = (imageview) findviewbyid(r.id.iv_logo);
  mdesctv = (textview) findviewbyid(r.id.tv_desc);
  mopenbtn = (button) findviewbyid(r.id.btn_open);

 }

 /**
  * 卡牌文本介绍打开效果:注意旋转角度
  */
 private void initopenanim() {
  //从0到90度,顺时针旋转视图,此时reverse参数为true,达到90度时动画结束时视图变得不可见,
  openanimation = new rotate3danimation(0, 90, centerx, centery, depthz, true);
  openanimation.setduration(duration);
  openanimation.setfillafter(true);
  openanimation.setinterpolator(new accelerateinterpolator());
  openanimation.setanimationlistener(new animationlistener() {

   @override
   public void onanimationstart(animation animation) {

   }

   @override
   public void onanimationrepeat(animation animation) {

   }

   @override
   public void onanimationend(animation animation) {
    mlogoiv.setvisibility(view.gone);
    mdesctv.setvisibility(view.visible);

    //从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见
    rotate3danimation rotateanimation = new rotate3danimation(270, 360, centerx, centery, depthz, false);
    rotateanimation.setduration(duration);
    rotateanimation.setfillafter(true);
    rotateanimation.setinterpolator(new decelerateinterpolator());
    mcontentrl.startanimation(rotateanimation);
   }
  });
 }

 /**
  * 卡牌文本介绍关闭效果:旋转角度与打开时逆行即可
  */
 private void initcloseanim() {
  closeanimation = new rotate3danimation(360, 270, centerx, centery, depthz, true);
  closeanimation.setduration(duration);
  closeanimation.setfillafter(true);
  closeanimation.setinterpolator(new accelerateinterpolator());
  closeanimation.setanimationlistener(new animationlistener() {

   @override
   public void onanimationstart(animation animation) {

   }

   @override
   public void onanimationrepeat(animation animation) {

   }

   @override
   public void onanimationend(animation animation) {
    mlogoiv.setvisibility(view.visible);
    mdesctv.setvisibility(view.gone);

    rotate3danimation rotateanimation = new rotate3danimation(90, 0, centerx, centery, depthz, false);
    rotateanimation.setduration(duration);
    rotateanimation.setfillafter(true);
    rotateanimation.setinterpolator(new decelerateinterpolator());
    mcontentrl.startanimation(rotateanimation);
   }
  });
 }

 public void onclickview(view v) {
  //以旋转对象的中心点为旋转中心点,这里主要不要再oncreate方法中获取,因为视图初始绘制时,获取的宽高为0
  centerx = mcontentrl.getwidth()/2;
   centery = mcontentrl.getheight()/2;
   if (openanimation == null) {
   initopenanim();
   initcloseanim();
  }

   //用作判断当前点击事件发生时动画是否正在执行
  if (openanimation.hasstarted() && !openanimation.hasended()) {
   return;
  }
  if (closeanimation.hasstarted() && !closeanimation.hasended()) {
   return;
  }

  //判断动画执行
  if (isopen) {
   mcontentrl.startanimation(closeanimation);

  }else {

   mcontentrl.startanimation(openanimation);
  }

  isopen = !isopen;
  mopenbtn.settext(isopen ? "关闭" : "打开");
 }
}

代码中已对核心的地方做了注释解释,主要弄清楚 rotate3danimation构造参数中的 fromdegrees和todegrees、depthz、reverse参数,同时在动画中设置了速度插播器,如动画的前半程使用加速器 accelerateinterpolator,后半程使用减速器 decelerateinterpolator,使动画体验更加人性化。

以上就是本文的全部内容,希望对大家的学习android软件编程有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网