分享一则最近流行的笑话:

最新科学研究表明:寒冷可以使人保持年轻,楼下的王大爷表示虽然今年已经60多岁了,但是仍然冷的跟孙子一样。

呃。好吧,这个冬天确实有点冷,在广州活生生的把我这个原生北方人,冻成一条狗。(研究表明:寒冷可以让人类基因突变。。。。)

好了不扯了。前些日子有朋友让我写博客来分析一下这个仿MIUI的时钟,从中学到了一些炫酷效果的实现。

本项目地址:https://github.com/githubwing/compassView

那么是啥3D效果呢,先来看看效果图,额。。有好多个:



这里写图片描述

其实后两个都是png来的。。

转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50590051

那么请问,看到图形的变换,你想到了什么?

没错!就是Matrix。

关于Matrix你可以到爱哥的博客了解到及其详细的讲解(谢谢爱哥!)。

下面我们就来研究一下如何用矩阵,实现这个3d的效果。

首先新建自定义view类。


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();
}
}

然后在圆心画一个圆出来

 @Override
protected void onDraw(Canvas canvas) { mCenterX = getWidth() / 2;
mCenterY = getHeight() / 2;
canvas.drawCircle(mCenterX,mCenterY,100,mPaint);
}

现在是这样的:

我们知道,处理一个图片的时候(切错)可以使用矩阵来处理,同时处理X,Y的话可以使用Camera类,camera可以生成一个指定效果的矩阵。直接来看用法:

private Camera mCamera;
private Matrix mMatrix; mMatrix = new Matrix();
mCamera = new Camera();

在onDraw里 把camera给旋转一下,并把生成的矩阵给一个矩阵。再把矩阵应用到canvas,看一下效果。

        mMatrix.reset();
mCamera.save();
mCamera.rotateX(10);
mCamera.rotateY(20);
mCamera.getMatrix(mMatrix);
mCamera.restore();
//将矩阵作用于整个canvas
canvas.concat(mMatrix);
```
这里写图片描述
![这里写图片描述](http://img.blog.csdn.net/20160127001011557)
呃。。。确实是变形了。。但是好像不是我们想要的结果?
这是因为,矩阵的变换坐标总从左上角(0,0)开始。所以我们要把变换的坐标改为中心点,方法如下:
    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:

 @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);
} 哈哈。。看看是什么效果:
这里写图片描述
![这里写图片描述](http://img.blog.csdn.net/20160127002007112) 什么鬼,怎么跟转硬币一样。 因为旋转的X,Y给的太大了呗。所以要约束一下。 定义一个旋转最大值

private float mCanvasMaxRotateDegree = 20;

再用percent思想(前面博客有提到),来处理手指触摸点和这个度数变化的关系:

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 调用此函数即可。

此时,完整的代码如下:

    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?

说搞就搞!

在原有类上进行修改

给一个好看的底色,画一条线

        mBgColor = Color.parseColor("#227BAE");
canvas.drawLine(mCenterX,100,mCenterX,130,mPaint);

这里写图片描述



嗯。不错 有条线了。微调下间距,旋转画布,画出整个圆形来:

//保存坐标系
canvas.save();
for (int i = 0; i < 120; i++) {
canvas.rotate(3,mCenterX,mCenterY);
canvas.drawLine(mCenterX, 150, mCenterX, 170, mPaint);
}
//恢复坐标系
canvas.restore();



嗯。。看起来想点样子了。 接下来调整透明度。

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 把之前画弧的方法提出来。

画一个紧挨着的圆

private void drawCircle(Canvas canvas) {

mPaint.setAlpha(255);

canvas.drawCircle(mCenterX,213,10,mPaint);

}

这里写图片描述



不错不错,给点动态效果吧,让圆点跟着我们触摸的地方走。怎么做呢。。 当然还是旋转画布了!

这里需要注意的是触摸点与12点钟方向形成的夹角计算。画图分析一下



可以看到 我们只需要调用Math.atan方法即可算出a的弧度,再将其转换为角度即可,在进行3D旋转之前,旋转画布:

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效果看起来有点奇怪。那就给他中间加点东西吧! 比如一个指针。

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);
}

最后大功告成!!! 看效果!

这里写图片描述

如果你喜欢我的博客,请点击关注。欢迎评论~~

下一篇! 手把手教你做一个qq下拉抢红包:打开链接

一个炫字都不够??!!!手把手带你打造3D自定义view的更多相关文章

  1. wing带你玩转自定义view系列(1) 仿360内存清理效果

    本篇是接自 手把手带你做自定义view系列 宗旨都是一样,带大家一起来研究自定义view的实现,与其不同的是本系列省去了简单的坐标之类的讲解,重点在实现思路,用简洁明了的文章,来与大家一同一步步学习. ...

  2. wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果

    上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个  两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingicho ...

  3. wing带你玩转自定义view系列(3)模仿微信下拉眼睛

    发现了爱神的自定义view系列,我只想说一个字:凸(艹皿艹 ) !!相见恨晚啊,早看到就不会走这么多弯路了 另外相比之下我这完全是小儿科..所以不说了,这篇是本系列完结篇....我要从零开始跟随爱哥脚 ...

  4. 手把手带你打造一个 Android 热修复框架(上篇)

    本文来自网易云社区 作者:王晨彦 前言 热修复和插件化是目前 Android 领域很火热的两门技术,也是 Android 开发工程师必备的技能. 目前比较流行的热修复方案有微信的 Tinker,手淘的 ...

  5. 手把手带你打造一个 Android 热修复框架

    本文来自网易云社区 作者:王晨彦 Application 处理 上面我们已经对所有 class 文件插入了 Hack 的引用,而插入 dex 是在 Application 中,Application ...

  6. 手把手带你使用JS-SDK自定义微信分享效果

    https://www.cnblogs.com/backtozero/p/7064247.html

  7. 你也可以自己写一个可爱 & 小资风格的Android加载等待自定义View - 转

    http://blog.csdn.net/carson_ho/article/details/77712072

  8. 手把手带你做一个超炫酷loading成功动画view Android自定义view

    写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...

  9. 手把手带你画一个 时尚仪表盘 Android 自定义View

    拿到美工效果图,咱们程序员就得画得一模一样. 为了不被老板喷,只能多练啊. 听说你觉得前面几篇都so easy,那今天就带你做个相对比较复杂的. 转载请注明出处:http://blog.csdn.ne ...

随机推荐

  1. Python 字符串字典内置函数&方法

    Python字典包含了以下内置函数: 序号 函数及描述 1 cmp(dict1, dict2)比较两个字典元素. 2 len(dict)计算字典元素个数,即键的总数. 3 str(dict)输出字典可 ...

  2. 无法启动postgresql的错误

    chown postgres /etc/ssl/private/ssl-cert-snakeoil.key chgrp postgres /etc/ssl/private/ssl-cert-snake ...

  3. 深入Java虚拟机(4)——网络移动性

    一.软件应用程序发展的几个阶段 软件应用程序发展经历了如下几个阶段: 服务于多个终端用户的大型计算机系统 孤立的个人计算机上运行孤立的软件 客户机/服务器模式 分布式处理模式 内容服务模式(网络移动性 ...

  4. [CSDN_Markdown] 使用LaTeX写矩阵

    简介 LaTeX 的公式功能非常强大,一次性讲全不是件容易的事情.将LaTeX 的这些功能分成较小的相互独立的部分来讲,一方面方便大家单独查阅:另一方面,所有[CSDN_Markdown]相关的文章都 ...

  5. ROS探索总结(十九)——如何配置机器人的导航功能

    1.概述 ROS的二维导航功能包,简单来说,就是根据输入的里程计等传感器的信息流和机器人的全局位置,通过导航算法,计算得出安全可靠的机器人速度控制指令.但是,如何在特定的机器人上实现导航功能包的功能, ...

  6. IMDG产品功能扩展

    开源IMDG通常都提供了SPI或其他接口,供用户自行扩展.以Hazelcast为例,我们可以用一些好玩的小工具增强其查询.Map和后端持久化的功能.这些小工具虽然看起来很小,但功能也非常强大. SQL ...

  7. C++ 虚函数表 多重继承

    上次研究的是单继承的情况,这次研究多重继承下的虚函数表的排列情况. 这次A,A1,A2,B这几个类的继承关系如下图: 测试代码如下: #include<iostream> using na ...

  8. 64位Linux下安装mysql-5.7.13-linux-glibc2.5-x86_64 || 转载:http://www.cnblogs.com/gaojupeng/p/5727069.html

    由于公司临时让将Oracle的数据移植到mysql上面,所以让我在公司服务器上面安装一下mysql.下面就是我的安装过程以及一些错误解决思路.其实对于不同版本安装大体都有差不多. 1. 从官网下载 m ...

  9. cocos2dx 3.2之Lua打飞机项目

    1          创建lua打飞机项目 cocos new T32Lua -dE:\Installed\cocos2d-x-3.2\cocos2d-x-3.2\projects -l lua 2 ...

  10. 【NPR】漫谈轮廓线的渲染

    写在前面 好久没写文章.最近在看<Real Time Rendering, third edition>这本书,看到了NPR这一章就想顺便记录下一些常见的轮廓线渲染的方法. 在非真实感渲染 ...