一个炫字都不够??!!!手把手带你打造3D自定义view
2016-01-27 11:07
525 查看
分享一则最近流行的笑话:
最新科学研究表明:寒冷可以使人保持年轻,楼下的王大爷表示虽然今年已经60多岁了,但是仍然冷的跟孙子一样。
呃。好吧,这个冬天确实有点冷,在广州活生生的把我这个原生北方人,冻成一条狗。(研究表明:寒冷可以让人类基因突变。。。。)
好了不扯了。前些日子有朋友让我写博客来分析一下这个仿MIUI的时钟,从中学到了一些炫酷效果的实现。
https://github.com/AvatarQing/MiClockView 感谢原作者的开源精神!
那么是啥3D效果呢,先来看看效果图,额。。有好多个:
其实后两个都是png来的。。
转载请注明出处:/article/3637916.html
那么请问,看到图形的变换,你想到了什么?
没错!就是Matrix。
关于Matrix你可以到爱哥的博客了解到及其详细的讲解(谢谢爱哥!)。
下面我们就来研究一下如何用矩阵,实现这个3d的效果。
现在是这样的:
我们知道,处理一个图片的时候(切错)可以使用矩阵来处理,同时处理X,Y的话可以使用Camera类,camera可以生成一个指定效果的矩阵。直接来看用法:
在onDraw里 把camera给旋转一下,并把生成的矩阵给一个矩阵。再把矩阵应用到canvas,看一下效果。
呃。。。确实是变形了。。但是好像不是我们想要的结果?
这是因为,矩阵的变换坐标总从左上角(0,0)开始。所以我们要把变换的坐标改为中心点,方法如下:
此时的效果看起来像是向左倾斜了:
接下来让他跟随手指移动,重写onTouchEvent:
哈哈。。看看是什么效果:
什么鬼,怎么跟转硬币一样。 因为旋转的X,Y给的太大了呗。所以要约束一下。
再用percent思想(前面博客有提到),来处理手指触摸点和这个度数变化的关系:
最后将TouchEvent里面的ACTION_MOVE 调用此函数即可。
此时,完整的代码如下:
简简单单100行代码,实现了3D效果的view:
比如,把我的PanelView加上这个效果:
哗!瞬间高大上!
那么,你要不要跟我趁热来一发自定义view?
说搞就搞!
嗯。不错 有条线了。微调下间距,旋转画布,画出整个圆形来:
嗯。。看起来想点样子了。 接下来调整透明度。
哈哈。。有没有点意思呢。。
我们画个圆球上去!画之前先ctrl + alt + m 把之前画弧的方法提出来。
画一个紧挨着的圆
不错不错,给点动态效果吧,让圆点跟着我们触摸的地方走。怎么做呢。。 当然还是旋转画布了!
这里需要注意的是触摸点与12点钟方向形成的夹角计算。画图分析一下
可以看到 我们只需要调用Math.atan方法即可算出a的弧度,再将其转换为角度即可,在进行3D旋转之前,旋转画布:
现在看一下效果:
效果出来了,但是还美中不足呀。 因为中间太空了,所以这个3D效果看起来有点奇怪。那就给他中间加点东西吧! 比如一个指针。
最后大功告成!!! 看效果!
如果你喜欢我的博客,请点击关注。欢迎评论~~
本项目地址:点击打开
最新科学研究表明:寒冷可以使人保持年轻,楼下的王大爷表示虽然今年已经60多岁了,但是仍然冷的跟孙子一样。
呃。好吧,这个冬天确实有点冷,在广州活生生的把我这个原生北方人,冻成一条狗。(研究表明:寒冷可以让人类基因突变。。。。)
好了不扯了。前些日子有朋友让我写博客来分析一下这个仿MIUI的时钟,从中学到了一些炫酷效果的实现。
https://github.com/AvatarQing/MiClockView 感谢原作者的开源精神!
那么是啥3D效果呢,先来看看效果图,额。。有好多个:
其实后两个都是png来的。。
转载请注明出处:/article/3637916.html
那么请问,看到图形的变换,你想到了什么?
没错!就是Matrix。
关于Matrix你可以到爱哥的博客了解到及其详细的讲解(谢谢爱哥!)。
下面我们就来研究一下如何用矩阵,实现这个3d的效果。
首先新建自定义view类。
[code]public class TDView extends View { private Paint mPaint; private int mCenterX; private int mCenterY; public TDView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); } }
然后在圆心画一个圆出来
[code] @Override protected void onDraw(Canvas canvas) { mCenterX = getWidth() / 2; mCenterY = getHeight() / 2; canvas.drawCircle(mCenterX,mCenterY,100,mPaint); }
现在是这样的:
我们知道,处理一个图片的时候(切错)可以使用矩阵来处理,同时处理X,Y的话可以使用Camera类,camera可以生成一个指定效果的矩阵。直接来看用法:
[code]private Camera mCamera; private Matrix mMatrix; mMatrix = new Matrix(); mCamera = new Camera();
在onDraw里 把camera给旋转一下,并把生成的矩阵给一个矩阵。再把矩阵应用到canvas,看一下效果。
[code] mMatrix.reset(); mCamera.save(); mCamera.rotateX(10); mCamera.rotateY(20); mCamera.getMatrix(mMatrix); mCamera.restore(); //将矩阵作用于整个canvas canvas.concat(mMatrix);
呃。。。确实是变形了。。但是好像不是我们想要的结果?
这是因为,矩阵的变换坐标总从左上角(0,0)开始。所以我们要把变换的坐标改为中心点,方法如下:
[code] mMatrix.reset(); mCamera.save(); mCamera.rotateX(10); mCamera.rotateY(20); mCamera.getMatrix(mMatrix); mCamera.restore(); //改变矩阵作用点 mMatrix.preTranslate(-mCenterX, -mCenterY); mMatrix.postTranslate(mCenterX, mCenterY); canvas.concat(mMatrix);
此时的效果看起来像是向左倾斜了:
接下来让他跟随手指移动,重写onTouchEvent:
[code] @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_MOVE: { //这里将camera旋转的变量赋值 mCanvasRotateY = y; mCanvasRotateX = x; invalidate(); return true; } case MotionEvent.ACTION_UP: { //这里将camera旋转的变量赋值 mCanvasRotateY = 0; mCanvasRotateX = 0; invalidate(); return true; } } return super.onTouchEvent(event); }
哈哈。。看看是什么效果:
什么鬼,怎么跟转硬币一样。 因为旋转的X,Y给的太大了呗。所以要约束一下。
定义一个旋转最大值
[code] private float mCanvasMaxRotateDegree = 20;
再用percent思想(前面博客有提到),来处理手指触摸点和这个度数变化的关系:
[code]private void rotateCanvasWhenMove(float x, float y) { float dx = x - mCenterX; float dy = y - mCenterY; float percentX = dx / mCenterX; float percentY = dy /mCenterY; if (percentX > 1f) { percentX = 1f; } else if (percentX < -1f) { percentX = -1f; } if (percentY > 1f) { percentY = 1f; } else if (percentY < -1f) { percentY = -1f; } mCanvasRotateY = mCanvasMaxRotateDegree * percentX; mCanvasRotateX = -(mCanvasMaxRotateDegree * percentY); }
最后将TouchEvent里面的ACTION_MOVE 调用此函数即可。
此时,完整的代码如下:
[code] private int mCenterX; private int mCenterY; private float mCanvasRotateX = 0; private float mCanvasRotateY = 0; private float mCanvasMaxRotateDegree = 20; private Matrix mMatrix = new Matrix(); private Camera mCamera = new Camera(); private Paint mPaint; public TDView(Context context) { super(context); } public TDView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mCanvasMaxRotateDegree = 20; } @Override protected void onDraw(Canvas canvas) { mCenterX = getWidth() / 2; mCenterY = getHeight() / 2; rotateCanvas(canvas); canvas.drawCircle(mCenterX, mCenterY, 100, mPaint); } private void rotateCanvas(Canvas canvas) { mMatrix.reset(); mCamera.save(); mCamera.rotateX(mCanvasRotateX); mCamera.rotateY(mCanvasRotateY); mCamera.getMatrix(mMatrix); mCamera.restore(); mMatrix.preTranslate(-mCenterX, -mCenterY); mMatrix.postTranslate(mCenterX, mCenterY); canvas.concat(mMatrix); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: { rotateCanvasWhenMove(x, y); return true; } case MotionEvent.ACTION_MOVE: { rotateCanvasWhenMove(x, y); invalidate(); return true; } case MotionEvent.ACTION_UP: { mCanvasRotateY = 0; mCanvasRotateX = 0; invalidate(); return true; } } return super.onTouchEvent(event); } private void rotateCanvasWhenMove(float x, float y) { float dx = x - mCenterX; float dy = y - mCenterY; float percentX = dx / mCenterX; float percentY = dy /mCenterY; if (percentX > 1f) { percentX = 1f; } else if (percentX < -1f) { percentX = -1f; } if (percentY > 1f) { percentY = 1f; } else if (percentY < -1f) { percentY = -1f; } mCanvasRotateY = mCanvasMaxRotateDegree * percentX; mCanvasRotateX = -(mCanvasMaxRotateDegree * percentY); } }
简简单单100行代码,实现了3D效果的view:
接下来做什么呢?
当然是把这个效果加到我们的自定义view里面!比如,把我的PanelView加上这个效果:
哗!瞬间高大上!
那么,你要不要跟我趁热来一发自定义view?
说搞就搞!
在原有类上进行修改
给一个好看的底色,画一条线[code] mBgColor = Color.parseColor("#227BAE"); canvas.drawLine(mCenterX,100,mCenterX,130,mPaint);
嗯。不错 有条线了。微调下间距,旋转画布,画出整个圆形来:
[code]//保存坐标系 canvas.save(); for (int i = 0; i < 120; i++) { canvas.rotate(3,mCenterX,mCenterY); canvas.drawLine(mCenterX, 150, mCenterX, 170, mPaint); } //恢复坐标系 canvas.restore();
嗯。。看起来想点样子了。 接下来调整透明度。
[code]canvas.save(); for (int i = 0; i < 120; i++) { //根据i调整透明度alpha mPaint.setAlpha(255-(mAlpha * i/120)); canvas.drawLine(mCenterX, 150, mCenterX, 170, mPaint); canvas.rotate(3,mCenterX,mCenterY); } canvas.restore();
哈哈。。有没有点意思呢。。
我们画个圆球上去!画之前先ctrl + alt + m 把之前画弧的方法提出来。
画一个紧挨着的圆
[code] private void drawCircle(Canvas canvas) { mPaint.setAlpha(255); canvas.drawCircle(mCenterX,213,10,mPaint); }
不错不错,给点动态效果吧,让圆点跟着我们触摸的地方走。怎么做呢。。 当然还是旋转画布了!
这里需要注意的是触摸点与12点钟方向形成的夹角计算。画图分析一下
可以看到 我们只需要调用Math.atan方法即可算出a的弧度,再将其转换为角度即可,在进行3D旋转之前,旋转画布:
[code]protected void onDraw(Canvas canvas) { canvas.drawColor(mBgColor); mCenterX = getWidth() / 2; mCenterY = getHeight() / 2; Log.e("wing",alpha+""); canvas.rotate((float) alpha,mCenterX,mCenterY); alpha = Math.atan((mTouchX-mCenterX)/(mCenterY-mTouchY)); alpha = Math.toDegrees(alpha); if(mTouchY>mCenterY){ alpha = alpha+180; }
现在看一下效果:
效果出来了,但是还美中不足呀。 因为中间太空了,所以这个3D效果看起来有点奇怪。那就给他中间加点东西吧! 比如一个指针。
[code] private void drawPath(Canvas canvas) { mPath.moveTo(mCenterX,223); mPath.lineTo(mCenterX-30,mCenterY); mPath.lineTo(mCenterX,2*mCenterY-223); mPath.lineTo(mCenterX+30,mCenterY); mPath.lineTo(mCenterX,233); mPath.close(); canvas.drawPath(mPath,mPaint); mPaint.setColor(Color.parseColor("#55227BAE")); canvas.drawCircle(mCenterX,mCenterY,20,mPaint); }
最后大功告成!!! 看效果!
如果你喜欢我的博客,请点击关注。欢迎评论~~
本项目地址:点击打开
相关文章推荐
- git tortoisegit的使用方法
- 百度地图API地点搜索-获取经纬度
- canvas绘制中的API
- 衡量企业应用数据库性能的6大指标
- 深度学习(十八)基于R-CNN的物体检测-CVPR 2014-未完待续
- mysql 日期函数相关 及一个小sql写法
- 深度学习(十七)基于改进Coarse-to-fine CNN网络的人脸特征点定位-ICCV 2013
- 操作系统课程设计之二级文件系统演示
- Xcode重构功能怎么用
- 深度学习(十六)基于2-channel network的图片相似度判别-CVPR 2015
- Aircrack除破解WiFi密码外的趣味玩法
- javascript中的3种继承实现方法
- 深度学习(十五)基于DCNN的人脸特征点定位-CVPR 2013
- java中的封装类
- 5-26 单词长度
- 高仿58加载动画
- IOS常量
- QTP检查点使用
- WPF中控件ListView和DataGrid典型属性介绍
- swift自学笔记(五)(重写属性、final)