Android 立方体翻转效果
2016-02-23 23:57
253 查看
今天我们来看看如何实现一个立方体翻转的效果,如图
![](http://ww2.sinaimg.cn/large/5dd54131gw1ewhzt3daq7g20f00qob2a.gif)
看上去很麻烦,实际上实现起来还是蛮轻松的。
这里我们使用到的有两个类。
我们先从摄像头上的角度分析:
正常情况下,我们是这么看画面的(那个电池一样的东西就当是摄像头吧)
![](https://segmentfault.com/img/bVp6Nm)
我们要产生立方体的效果,那逻辑上应该是这么看:
![](https://segmentfault.com/img/bVp6Nv)
Camera提供了几个接口,我们这使用到的接口有两个:
Rotate 旋转
Translate 平移
这两个函数的操作都对
这里我们首先要有2个View。xml结构入下:
SplashLayout就是我的自定义布局,用来绘制立方体效果的布局。
我们把第一个view作为
具体代码入下:
这段代码放到
其中,
到 1.0 的过程,方便插入器的使用。
这里来解释下我们的过程。
起始状态
绕Y轴正方向转90度
画布x轴移动到width的位置。
可以参照上图中的
终点状态是这样:
绕Y轴正方向0度。
画布x轴移动到0的位置。
可以参考上图中的画布的状态。
综上所述,我们设置转动角度
这时候我们考虑平移的情况,这个情况会比较复杂,因为我们这里有两种平移方式,
这里我们说下区别,如果移动摄像机,会导致图像的投影发生变化,举个例子:
比如我们已经在投影上绕Y轴旋转90度,如果移动X轴的话,看如下图的区别:
1、未平移摄像机
![](https://segmentfault.com/img/bVp6QZ)
2、平移摄像机
![](https://segmentfault.com/img/bVp6Rb)
从图上我们知道,这个旋转过的画布的前端和后端我们都是可以看见的,这当然不符合我们要求,那么我们直接平移画布是什么意思呢?
我们知道对摄像机做了操作之后,应用到画布上,实际是画一个画布的投影,直接移动画布的话,就是改变其坐标系系统,达到效果,我们可以理解为同时对摄像机和view进行平移,最终达到的效果就是摄像头相对view的位置和
我们看代码虽然我们平移的是画布,但是我们平移的过程中确是使用移动摄像机的方式来绘制投影,这又是为什么呢?
我们从三角函数的投影来解释这个问题。
首先看见我平移摄像头的方式是线性的,也就是
被旋转的角就是
![](https://segmentfault.com/img/bVp6RF)
它是一个三角函数。变化趋势先快后慢,因此我们在旋转过程中会看见右边露出背景,造成视觉上的不友好,怎么解决这个问题呢?
这时候就借助我们的摄像机平移的投影方式。
![](https://segmentfault.com/img/bVp6RT)
这里绿色的线是我们的投影线,它的投影长度比
我们的
做UI的效果,特别需要一些比较好的数据基础,在图像处理中,搞清楚透视、矩阵的一些计算方式和概念非常重要,今天我们介绍了利用
https://github.com/geminiwen/AndroidCubeDemo
![](http://ww2.sinaimg.cn/large/5dd54131gw1ewhzt3daq7g20f00qob2a.gif)
看上去很麻烦,实际上实现起来还是蛮轻松的。
这里我们使用到的有两个类。
android.graphic.Camera这是在图像学概念里的摄像机,这是一个
透视摄像机。
android.graphic.Matrix矩阵,用来表示图像的变化。
头疼的钻研路开始
我们先从摄像头上的角度分析:正常情况下,我们是这么看画面的(那个电池一样的东西就当是摄像头吧)
我们要产生立方体的效果,那逻辑上应该是这么看:
Camera提供了几个接口,我们这使用到的接口有两个:
Rotate 旋转
Translate 平移
这两个函数的操作都对
画布的!
这里我们首先要有2个View。xml结构入下:
[code]<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 }
这段代码放到
ViewGroup的
dispatchDraw方法里即可,因为
ViewGroup只能在
dispatchDraw方法中绘制子视图。
其中,
canvas代表画布,
interpolation代表动画从0.0
到 1.0 的过程,方便插入器的使用。
这里来解释下我们的过程。
View状态变换
起始状态background是这样的:
绕Y轴正方向转90度
画布x轴移动到width的位置。
可以参照上图中的
画布2的状态。
终点状态是这样:
绕Y轴正方向0度。
画布x轴移动到0的位置。
可以参考上图中的画布的状态。
旋转问题
综上所述,我们设置转动角度sFinalDegree为90。
interpolation从0到1的过程,
background的rotate就变成了从
90到
0的过程。
平移问题
这时候我们考虑平移的情况,这个情况会比较复杂,因为我们这里有两种平移方式,平移摄像机或者
直接平移画布。
这里我们说下区别,如果移动摄像机,会导致图像的投影发生变化,举个例子:
比如我们已经在投影上绕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
相关文章推荐
- Android进阶之抢购倒计时功能
- <<Android 开发艺术探索>> 第一章 Actiivty的生命周期和启动模式
- Android版本和API Level
- 在android中读取word、excel、pdf
- Android自定义控件
- Android中的动态加载机制
- Android中插件开发篇之----类加载器
- 关于android基础教程一书的初步解读后发现的一些问题
- android:TableLayout表格布局详解
- [android] 点击事件的四种写法
- android listview图片错位原理及解决方法
- 其他零散学习-Android四大组件
- Android 6 Marshmallow USB调试授权
- 解决Android Studio的ADB not responding错误
- android中的类加载器,以及加载机制
- Android学习心得第二课
- 转行自学android,Day3-蒙圈
- Android流媒体播放器介绍
- Android序列化之Serializable和Parcelable
- android开源框架之PullToRefresh概述