Android -- 贝塞尔使圆渐变为桃心
1,我们上一篇介绍了贝塞尔曲线推到原理和在Android里的简单使用,今天就和来写写贝塞尔曲线的实际应用,今天实现的效果图如下:
2,思路分析
我们知道首先我们的view是一个圆,这里的圆其实是由四块三阶贝塞尔曲线组成的,左上、右上、左下、右下这四块贝塞尔曲线组成,那么让我们来开始吧
- 准备阶段
创建一个类MyViewCircle继承自View,重写构造方法,重写onDraw()方法
- public class MyViewCircle extends View {
- public MyViewCircle(Context context) {
- this(context, null);
- }
- public MyViewCircle(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyViewCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- }
- }
- 绘制X、Y轴
由于我们的view是展示在屏幕的正中央的,为了我们以后标识点方便,这里我们以屏幕的正中心为(0,0)坐标绘制出来
在onSizeChange()方法中获得mCenterX、mCenterY的坐标,绘制X,Y轴,代码如下:
- private int mCenterX;
- private int mCenterY;
- private Paint mPaint;
- //省略代码.........................
- //初始化画笔
- mPaint = new Paint();
- mPaint.setColor(Color.BLACK);
- mPaint.setStrokeWidth(3);
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setAntiAlias(true);
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- //初始化坐标系
- mCenterX = getWidth() / 2;
- mCenterY = getHeight() / 2;
- }
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.save();
- //绘制x,y轴坐标系
- canvas.drawLine(mCenterX, 0, mCenterX, getHeight(), mPaint);
- canvas.drawLine(0, mCenterY, getWidth(), mCenterY, mPaint);
- canvas.restore();
- }
运行效果如下:
- 从三阶贝塞尔曲线得到半圆的效果
我们上一篇简单的介绍了下三阶贝塞尔,当我们的两个控制点距离数据点为一下坐标时我们绘制出来的曲线是类似于四分之一圆弧的,效果图如下:
关于怎么计算出这两个控制点相对于数据点的相对坐标的,这是一个难点,不过还好,在stackoverflow上有人计算出来了,这是链接,我们可以得出一个常量0.552284749831,即相对于原点坐标,半径是mCircleRadius我们的坐标的0.55228倍,这里我为了方便,直接取了0.5,所以这就解释了为什么我们效果图中的圆有点瘪(保持微笑)
- 绘制数据点
这里我们四个数据点分别是的是半径为mCircleRadius,圆心坐标为(mCenterX,mCenterY)的圆与我们X、Y轴的焦点,绘制代码如下:
- private Paint mPaintCircle;
- private Paint mPaintPoint;
- private int mCircleRadius;
- private List<PointF> mPointDatas; //放置四个数据点的集合
- private List<PointF> mPointControlls;//方式8个控制点的集合
- //省略代码.....
- //初始化数据
- mPaintCircle = new Paint();
- mPaintCircle.setColor(Color.RED);
- mPaintCircle.setStrokeWidth(10);
- mPaintCircle.setStyle(Paint.Style.STROKE);
- mPaintCircle.setAntiAlias(true);
- mPaintPoint = new Paint();
- mPaintPoint.setColor(Color.BLACK);
- mPaintPoint.setStrokeWidth(5);
- mPaintPoint.setStyle(Paint.Style.FILL);
- mPaintPoint.setAntiAlias(true);
- mCircleRadius = 150;
- //在onSizeChange方法中初始化四个数据点
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- //初始化坐标系
- mCenterX = getWidth() / 2;
- mCenterY = getHeight() / 2;
- mPointDatas = new ArrayList<>();
- mPointControlls = new ArrayList<>();
- mPointDatas.add(new PointF(mCenterX, mCenterY - mCircleRadius));
- mPointDatas.add(new PointF(mCenterX + mCircleRadius, mCenterY));
- mPointDatas.add(new PointF(mCenterX, mCenterY + mCircleRadius));
- mPointDatas.add(new PointF(mCenterX - mCircleRadius, mCenterY));
- }
- //在onDraw方法中绘制数据点
- @Override
- protected void onDraw(Canvas canvas) {
- //绘制x,y轴坐标系
- canvas.drawLine(mCenterX, 0, mCenterX, getHeight(), mPaint);
- canvas.drawLine(0, mCenterY, getWidth(), mCenterY, mPaint);
- //绘制数据点
- for (int i = 0; i < mPointDatas.size(); i++) {
- canvas.drawPoint(mPointDatas.get(i).x, mPointDatas.get(i).y, mPaintPoint);
- }
- }
效果图如下:
- 绘制控制点
由我们上面的的到的常量0.552284749831,这里使用的是0.5,所以,代码如下
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- //初始化坐标系
- mCenterX = getWidth() / 2;
- mCenterY = getHeight() / 2;
- mPointDatas = new ArrayList<>();
- mPointControlls = new ArrayList<>();
- mPointDatas.add(new PointF(mCenterX, mCenterY - mCircleRadius));
- mPointDatas.add(new PointF(mCenterX + mCircleRadius, mCenterY));
- mPointDatas.add(new PointF(mCenterX, mCenterY + mCircleRadius));
- mPointDatas.add(new PointF(mCenterX - mCircleRadius, mCenterY));
- mPointControlls.add(new PointF(mCenterX + mCircleRadius / 2, mCenterY - mCircleRadius));
- mPointControlls.add(new PointF(mCenterX + mCircleRadius, mCenterY - mCircleRadius / 2));
- mPointControlls.add(new PointF(mCenterX + mCircleRadius, mCenterY + mCircleRadius / 2));
- mPointControlls.add(new PointF(mCenterX + mCircleRadius / 2, mCenterY + mCircleRadius));
- mPointControlls.add(new PointF(mCenterX - mCircleRadius / 2, mCenterY + mCircleRadius));
- mPointControlls.add(new PointF(mCenterX - mCircleRadius, mCenterY + mCircleRadius / 2));
- mPointControlls.add(new PointF(mCenterX - mCircleRadius, mCenterY - mCircleRadius / 2));
- mPointControlls.add(new PointF(mCenterX - mCircleRadius / 2, mCenterY - mCircleRadius));
- }
- //在onDraw方法中添加控制点的绘制
- @Override
- protected void onDraw(Canvas canvas) {
- //绘制x,y轴坐标系
- canvas.drawLine(mCenterX, 0, mCenterX, getHeight(), mPaint);
- canvas.drawLine(0, mCenterY, getWidth(), mCenterY, mPaint);
- //绘制数据点
- canvas.save();
- for (int i = 0; i < mPointDatas.size(); i++) {
- canvas.drawPoint(mPointDatas.get(i).x, mPointDatas.get(i).y, mPaintPoint);
- }
- //绘制控制点
- for (int i = 0; i < mPointControlls.size(); i++) {
- canvas.drawPoint(mPointControlls.get(i).x, mPointControlls.get(i).y, mPaintPoint);
- }
- }
绘制后效果图如下:
- 绘制三阶贝塞尔曲线
先来绘制右上角四分之一圆弧的贝塞尔曲线看看效果,在onDraw中调用如下代码:
- //利用三阶贝塞尔曲线实现画圆
- Path path = new Path();
- path.moveTo(mPointDatas.get(0).x, mPointDatas.get(0).y);
- path.cubicTo(mPointControlls.get(0).x, mPointControlls.get(0).y, mPointControlls.get(1).x, mPointControlls.get(1).y, mPointDatas.get(1)x, mPointDatas.get(1).y);
- //绘制
- canvas.drawPath(path, mPaintCircle);
看一下效果:
看到了吧 ,效果可以吧,然后我们继续来把后面三条弧线绘制玩,代码如下:
- //利用三阶贝塞尔曲线实现画圆
- Path path = new Path();
- path.moveTo(mPointDatas.get(0).x, mPointDatas.get(0).y);
- for (int i = 0; i < mPointDatas.size(); i++) {
- if (i == mPointDatas.size() - 1) {
- path.cubicTo(mPointControlls.get(2 * i).x, mPointControlls.get(2 * i).y, mPointControlls.get(2 * i + 1).x, mPointControlls.get(2 * i + 1).y, mPointDatas.get(0).x, mPointDatas.get(0).y);
- } else {
- path.cubicTo(mPointControlls.get(2 * i).x, mPointControlls.get(2 * i).y, mPointControlls.get(2 * i + 1).x, mPointControlls.get(2 * i + 1).y, mPointDatas.get(i + 1).x, mPointDatas.get(i + 1).y);
- }
- }
- canvas.drawPath(path, mPaintCircle);
效果如下:
- 改变数据点和控制点,重绘制view
这一步最关键,先来看看我们下面的动画效果
可以看到我们上面动画实现的效果移动有五个点变了:一个Y正轴上数据点改变,四个Y负轴控制点改变了,ok,知道了这些了我们基本上知道了怎么实现了,代码如下:
- private int mDuration = 1000; //动画总时间
- private int mCurrTime = 0; //当前已进行时间
- private int mCount = 100;//将总时间划分多少块
- private float mPiece = mDuration / mCount; //每一块的时间 ;
- //在onDraw()方法中动态的刷新view,有人肯定会问,120,80之类的怎么的出来的,我只能说调出来的好嘛(手动微笑),代码如下:
- //动态改变数据点和辅助点
- mCurrTime += mPiece;
- if (mCurrTime < mDuration) {
- mPointDatas.get(0).y += 120 / mCount;
- mPointControlls.get(2).x -= 20.0 / mCount;
- mPointControlls.get(3).y -= 80.0 / mCount;
- mPointControlls.get(4).y -= 80.0 / mCount;
- mPointControlls.get(5).x += 20.0 / mCount;
- postInvalidateDelayed((long) mPiece);
- }
ok,这样我们基本上全部完成了,看一下效果
ok,这样我们就实现这个效果了,有没有很简单,有需要源码的同学可以在我的Github下载,明天继续,See You Next Time!!!
Android -- 贝塞尔使圆渐变为桃心的更多相关文章
- Android ActionBar标题和渐变背景
需要在AndroidManifest.xml中设置 android:theme="@style/Theme.AppCompat" 如果提示找不到,请按下图设置: 至于如何引入的方法 ...
- 在Android系统中修改Android.mk使其同时编译rgb2565和rgb2888(向out/host/linux-x86/bin/下新增加一个工具命令)【转】
本文转载自:http://blog.csdn.net/mu0206mu/article/details/7514559 在Android系统中修改android.mk使其同时编译rgb2565和rgb ...
- Android 贝塞尔曲线解析
相信很多同学都知道"贝塞尔曲线"这个词,我们在很多地方都能经常看到.利用"贝塞尔曲线"可以做出很多好看的UI效果,本篇博客就让我们一起学习"贝塞尔曲线 ...
- android自定义进度圆与定时任务
先看代码:自定进度圆 public class ProgressCircle extends View { private Paint paint; private int strokewidth = ...
- Android 贝塞尔曲线 折线图
1.贝塞尔曲线:http://baike.baidu.com/view/60154.htm,在这里理解什么是贝塞尔曲线 2.直接上图: 3.100多行代码就可以画出贝塞尔曲线,直接上代码 packag ...
- Android Shape画圆,矩形
画圆环代码如下: 画圆环,外边的边界宽度大一点即可: <?xml version="1.0" encoding="utf-8"?> <shap ...
- Android -- 贝塞尔曲线公式的推导
1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...
- Android -- 贝塞尔二阶实现饿了么加入购物车效果
1,上周我们实现了简单的三阶贝塞尔曲线效果实例,今天是使用二阶贝塞尔曲线加动画实现的加入购物车效果,在码代码过程中出现了些问题,过一下和大家来探讨探讨,先看一下效果图 2,从上面的效果来看我们基本上可 ...
- Android -- 贝塞尔实现水波纹动画(划重点!!)
1,昨天看到了一个挺好的ui效果,是使用贝塞尔曲线实现的,就和大家来分享分享,还有,在写博客的时候我经常会把自己在做某种效果时的一些问题给写出来,而不是像很多文章直接就给出了解决方法,这里给大家解释一 ...
随机推荐
- C语言 extern4 全局数组
headB.h中: #ifndef headB_H #define headB_H ; ]={,,,,}; #endif .c文件中: #include "headB.h" #in ...
- python实现多变量线性回归(Linear Regression with Multiple Variables)
本文介绍如何使用python实现多变量线性回归,文章参考NG的视频和黄海广博士的笔记 现在对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为( x1,x2,..., ...
- 微信公众号平台接口开发:基础支持,获取access_token
新建Asp.net MVC 4.0项目 WeChatSubscript是项目UI层 WeChatTools是封装操作访问公众号接口的一些方法类库 获取AccssToken 我们要的得到AccessTo ...
- php文件上传分类
<?php/** * 文件上传类 * @author lijiamin * @time 2017-02-17 * @email 1195989301@qq.com */class Upload{ ...
- 使用jmeter进行APP接口测试经验总结
声明:我觉得文章不错想保存,如果带来不便请联系我. 使用工具: Fiddler.Jmeter 测试步骤: 1. 确认接口 从开发人员那里获取接口文档,接口文档应该包括完整的功能接口.接口请求方式 ...
- Activiti工作流(二)之常用操作
前面介绍了Activiti工作流的基本操作,但是在实际应用过程中,往往不满足项目需求,因此还需要了解一些其他的功能比如:连线.排他网关.并行网管.流程变量.个人任务及组任务的三种发布方式. 下面将介绍 ...
- 301、404、200、304、500HTTP状态
一些常见的状态码为: 200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - 服务器超时 下面提供 HTTP 状态码的完整列表.点击链接可了解详情.您也可以访问 HTTP 状态码上的 ...
- Cloud9vue&vux上传github小步骤
成功后创建出以下文件,再输入: git init 再输入:$ git remote add origin https://github.com/github用户名/vux1 然后:git add. 按 ...
- 初识Windous程序
文本框Label MaxLength 设置输入文本最大字符 Multiline 表示是否输入多行文本 passwodechar 指示在文本框显示的字符,而不是实际内容 ReadeOnly 表示是否可 ...
- 配置Server Side TAF
实验环境:Oracle 11.2.0.4 RAC 参考MOS文档: How To Configure Server Side Transparent Application Failover (文档 ...