Android 立方体翻转效果

今天我们来看看如何实现一个立方体翻转的效果,如图

看上去很麻烦,实际上实现起来还是蛮轻松的。
这里我们使用到的有两个类。

  1. android.graphic.Camera 这是在图像学概念里的摄像机,这是一个透视摄像机
  2. android.graphic.Matrix 矩阵,用来表示图像的变化。

头疼的钻研路开始

我们先从摄像头上的角度分析:
正常情况下,我们是这么看画面的(那个电池一样的东西就当是摄像头吧)


我们要产生立方体的效果,那逻辑上应该是这么看:

Camera提供了几个接口,我们这使用到的接口有两个:

  1. Rotate 旋转
  2. Translate 平移

这两个函数的操作都对画布的!
这里我们首先要有2个View。xml结构入下:

<cn.geminiwen.canvassupport.view.SplashLayout
        android:text="@string/hello_world"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000" >
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#f00">
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#0f0">
        </RelativeLayout>
</cn.geminiwen.canvassupport.view.SplashLayout>

SplashLayout就是我的自定义布局,用来绘制立方体效果的布局。

我们把第一个view作为backgroundView,第二个View作为foregroundView,使得效果是从backgroundView翻转到foregroundView

具体代码入下:

private void cube(Canvas canvas, double interpolation) {
        View foregroundView = getChildAt(0);
        View backgroundView = getChildAt(1);
        int width = getWidth();
        int height = getHeight();
        long drawingTime = getDrawingTime();
        float rotate;

        //begin drawForeground
        rotate = (float)(- sFinalDegree * interpolation);
        mCamera.save();
        mCamera.translate((float)(width - interpolation * width), 0, 0);
        mCamera.rotateY(rotate);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();

        mMatrix.postTranslate(0, height / 2);
        mMatrix.preTranslate(-width, -height / 2);
        canvas.save();
        canvas.concat(mMatrix);
        drawChild(canvas, foregroundView, drawingTime);
        canvas.restore();
        //end drawForeground

        //draw Background
        rotate = (float)(sFinalDegree - sFinalDegree * interpolation);
        mCamera.save();
        mCamera.translate((float)(-width * interpolation), 0, 0);
        mCamera.rotateY(rotate);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();

        mMatrix.postTranslate(width, height / 2);
        mMatrix.preTranslate(0, -height / 2);
        canvas.save();
        canvas.concat(mMatrix);
        drawChild(canvas, backgroundView, drawingTime);
        canvas.restore();
        //end draw Background

    }

这段代码放到ViewGroupdispatchDraw方法里即可,因为ViewGroup只能在dispatchDraw方法中绘制子视图。
其中,canvas代表画布,interpolation代表动画从0.0
到 1.0 的过程,方便插入器的使用。

这里来解释下我们的过程。

View状态变换

起始状态background是这样的:

  1. 绕Y轴正方向转90度
  2. 画布x轴移动到width的位置。

可以参照上图中的画布2的状态。

终点状态是这样:

  1. 绕Y轴正方向0度。
  2. 画布x轴移动到0的位置。

可以参考上图中的画布的状态。

旋转问题

综上所述,我们设置转动角度sFinalDegree为90。
interpolation从0到1的过程,
background的rotate就变成了从900的过程。

平移问题

这时候我们考虑平移的情况,这个情况会比较复杂,因为我们这里有两种平移方式,平移摄像机或者直接平移画布

这里我们说下区别,如果移动摄像机,会导致图像的投影发生变化,举个例子:
比如我们已经在投影上绕Y轴旋转90度,如果移动X轴的话,看如下图的区别:

1、未平移摄像机

2、平移摄像机


从图上我们知道,这个旋转过的画布的前端和后端我们都是可以看见的,这当然不符合我们要求,那么我们直接平移画布是什么意思呢?

我们知道对摄像机做了操作之后,应用到画布上,实际是画一个画布的投影,直接移动画布的话,就是改变其坐标系系统,达到效果,我们可以理解为同时对摄像机和view进行平移,最终达到的效果就是摄像头相对view的位置和1一样,但是我们的画布却平移了,这就达到了我们最终的要求。

我们看代码虽然我们平移的是画布,但是我们平移的过程中确是使用移动摄像机的方式来绘制投影,这又是为什么呢?

我们从三角函数的投影来解释这个问题。
首先看见我平移摄像头的方式是线性的,也就是y=kt这种方式,斜率一定,也就是随着时间变化,我平移的距离是线性增加的。那么考虑旋转的时候的投影情况:
被旋转的角就是角a,我们的画布长为width,那么画布的投影长度为 
width * cos(a)

它是一个三角函数。变化趋势先快后慢,因此我们在旋转过程中会看见右边露出背景,造成视觉上的不友好,怎么解决这个问题呢? 

这时候就借助我们的摄像机平移的投影方式。

这里绿色的线是我们的投影线,它的投影长度比cos(a) * width要长很多,因此它就可以让我们在旋转过程中不产生黑边,给人视觉上的饱满感,会让我们的视觉效果好很多。

我们的foregroundView就是一个backgroundView的逆向过程,因此使用类似的代码,然后假设interpolation是从1-0的过程即可,同时它的坐标系整体要往左移动一个屏幕。

总结

做UI的效果,特别需要一些比较好的数据基础,在图像处理中,搞清楚透视、矩阵的一些计算方式和概念非常重要,今天我们介绍了利用Camera来进行辅助我们进行矩阵的计算。

源码

https://github.com/geminiwen/AndroidCubeDemo 

时间: 2024-10-27 12:40:13

Android 立方体翻转效果的相关文章

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

在Android系统API中,有两个Camera类: android.graphics.Camera android.hardware.Camera 第二个应用于手机硬件中的相机相关的操作,本文讲述的是利用第一个Camera类实现中轴3D转换的卡牌翻转效果,开始之前,先看一下Android系统中的坐标系: 对应于三维坐标系中的三个方向,Camera提供了三种旋转方法: rotateX() rotateY() rotateX() 调用这三种方法,传入旋转角度参数,即可实现视图沿着坐标轴旋转的功能.

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

在Android系统API中,有两个Camera类: android.graphics.Camera android.hardware.Camera 第二个应用于手机硬件中的相机相关的操作,本文讲述的是利用第一个Camera类实现中轴3D转换的卡牌翻转效果,开始之前,先看一下Android系统中的坐标系: 对应于三维坐标系中的三个方向,Camera提供了三种旋转方法: rotateX() rotateY() rotateX() 调用这三种方法,传入旋转角度参数,即可实现视图沿着坐标轴旋转的功能.

【Android】android镜像翻转

Android镜像翻转指的是将屏幕进行水平的翻转,达到所有内容显示都会反向的效果,就像是在镜子中看到的界面一样.这种应用的使用场景相对比较受限,主要用在一些需要使用Android手机界面进行镜面投影的地方,比如说车载手机hud导航之类的. 镜像翻转的效果如下:      镜像水平翻转前后效果 在没办法对硬件进行直接翻转的时候,只能从代码进行着手.最先想到的方法是一种比较弱的实现方案,就是对界面进行截图,然后对截图进行翻转,再让其替换掉原先的界面,这种方法是可行的,但是会出现很严重的内存问题,因为

iOS动画特效之立方体翻转_IOS

先来看看效果: 下面进入正题,是时候展现真正的技术了: 首先在控制器里添加一个scrollView,再在scrollView上的对应位置上添加要展示的imageView(立方体视图组),当然也可以放上其它子控制器的view实现更多功能这个随意不是重点 //*******添加scrollView******* [self createScrollView]; //******创建立方体视图组****** [self createCubicViewArray]; //添加视图到scrollView上

android 2种效果求实现方法。。。有截图。。。

问题描述 android 2种效果求实现方法...有截图... ** 可以左右滑动,里面是文字,还可以上下滑动文字...我只做过图片的... ** ----------------------分割线----------------------------- 注意看图片边角(小半圆)...是怎么实现的,我已经确认过了图片是方形的,应该是覆盖了... 我不知道怎么覆盖的... 解决方案 android-support-v4.jar中的viewpager,里面是scrollview.覆盖,用relat

Flash CS3制作卡片翻转效果

在Flash讨论中一个流行的卡通效果:怎样让一个平面卡片按360度角旋转或翻转.要明白这个动画的方法是困难的.这不难想象, Flash从来就是两维的程序,而要添加一个三维的实例是不可能的,除非那个对象是在时间轴上重新手工绘制的.但是使用Flash,在所有的方法中,它不能真正的实现三维.下面来看看如何制作卡片翻转效果的. 示意图 1.首先画一个没有笔触的矩形,在第10帧插入关键帧.选择自由变形工具(q)然后选择扭曲子工具. 图1 2.按住Shift键,将顶部的角拉离形状.继续按住Shift键将底部

css3的图形3d翻转效果应用示例

css3的图形3d翻转效果应用示例  代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html" charset="utf-8" /> <title>css3 3d rotate</title> <style type="text/css&quo

PowerPoint设计 制作3D翻转效果教程

  PowerPoint演示文稿,之所以叫演示,就是因为要做给人看的,至于看完的效果如何,就要看制作者的用心设计呢,一个好演示文稿,除了图片与文字的相得益彰,动画过渡的完美组合,音乐与歌词的同步进行,内容与动画的相互呼应!PowerPoint的生动就在于动画演绎的完美,下面教大家一个3D翻转效果,希望大家在制作的过程能起到作用! 1.打开PowerPoint软件,找到插入. 2.按住ctrl插入多张图片. 3.插入之后按ctrl+a选中所有图片.( 注:一般情况下,刚插入之后都是全选状态) 4.

图片翻转效果具体实现代码

 想必大家对图片翻转效果都有所了解吧,其实很容易实现的,下面有个不错的示例,喜欢的朋友可以参考下 以下为程序代码:  代码如下: <!DOCTYPE html />  <html>  <head>  <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />  <meta http-equiv="X-UA-Compatib