热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

这篇文章主要介绍了Android利用Camera实现中轴3D卡牌翻转效果,需要的朋友可以参考下

在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布局文件:

<&#63;xml version="1.0" encoding="utf-8"&#63;>


 

布局中配置了卡牌正面的图片控件,卡牌背面的文本控件,以及他们的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 &#63; "关闭" : "打开");
 }
}

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

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


推荐阅读
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 集合的遍历方式及其局限性
    本文介绍了Java中集合的遍历方式,重点介绍了for-each语句的用法和优势。同时指出了for-each语句无法引用数组或集合的索引的局限性。通过示例代码展示了for-each语句的使用方法,并提供了改写为for语句版本的方法。 ... [详细]
author-avatar
赵丶宇森
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有