在某网站上看到一个效果,就是关键字的布局呈球状排布,并可以根据鼠标的移动而旋转。于是也想在Android实现同样的效果,顺便封装成通用的控件,说不定以后就可以用到了。
说干就干,大家先看看我的实现效果,Github地址:https://github.com/dgutkai/RollingBall.git,欢迎fork。
一、技术选型
开始我选择自定义一个View,在View的OnDraw方法中绘制球形,然而这种方法最大的一个缺点就是球形元素不能很好添加事件。于是改成现在的方法,即集成ViewGroup,将子控件的按照球形摆布,这样每一个子控件可以单独接受事件,也可以在XML任意布局控件。
二、球形布局理论推导
A、球面上每点的坐标(x, y, z)
由于我们显示的界面是一个平面,所以,z坐标将作为深度变量,也就是作为透明度和缩放的值。
B、手指上下滑,坐标点(x, y, z)变为(x1, y1, z1)
由于我们屏幕上只显示XOY平面,所以当我们上下滑动的时候,球将围绕X轴旋转。因此X坐标值不变,我们在YOZ平面上看Y坐标和Z坐标的变化。
如图所示,假设球绕X轴旋转了,那么得到新坐标为:
其中
利用三角函数公式展开:
将R1代入上式,
C、手指左右滑动,坐标点(x1, y1, z1)变为(x2, y2, z2)
和B同理,手指左右滑动,球绕Y轴旋转,Y坐标不变,X、Z坐标变换原理同上,可得到
D、使用代码实现
BollBean bb1 = bollBeans[i];
double rx1 = bb1.getBX();
double ry1= bb1.getBY()*Math.cos(a1)+bb1.getBZ()*(-Math.sin(a1));
double rz1= bb1.getBY()*Math.sin(a1)+bb1.getBZ()*Math.cos(a1);
double rx2= rx1*Math.cos(b1)+rz1*Math.sin(b1);
double ry2=ry1;
double rz2= rx1*(-Math.sin(b1))+rz1*Math.cos(b1);
bb1.setBX(rx2);
bb1.setBY(ry2);
bb1.setBZ(rz2);
代码中a1,b1分别表示球绕X轴和Y轴旋转的角度。这样将手指移动的距离近似为转动的角度,便能够得到随着手指转动的球了。
详细Demo可以到我的Github下载查看。