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 -- 贝塞尔使圆渐变为桃心的更多相关文章

  1. Android ActionBar标题和渐变背景

    需要在AndroidManifest.xml中设置 android:theme="@style/Theme.AppCompat" 如果提示找不到,请按下图设置: 至于如何引入的方法 ...

  2. 在Android系统中修改Android.mk使其同时编译rgb2565和rgb2888(向out/host/linux-x86/bin/下新增加一个工具命令)【转】

    本文转载自:http://blog.csdn.net/mu0206mu/article/details/7514559 在Android系统中修改android.mk使其同时编译rgb2565和rgb ...

  3. Android 贝塞尔曲线解析

    相信很多同学都知道"贝塞尔曲线"这个词,我们在很多地方都能经常看到.利用"贝塞尔曲线"可以做出很多好看的UI效果,本篇博客就让我们一起学习"贝塞尔曲线 ...

  4. android自定义进度圆与定时任务

    先看代码:自定进度圆 public class ProgressCircle extends View { private Paint paint; private int strokewidth = ...

  5. Android 贝塞尔曲线 折线图

    1.贝塞尔曲线:http://baike.baidu.com/view/60154.htm,在这里理解什么是贝塞尔曲线 2.直接上图: 3.100多行代码就可以画出贝塞尔曲线,直接上代码 packag ...

  6. Android Shape画圆,矩形

    画圆环代码如下: 画圆环,外边的边界宽度大一点即可: <?xml version="1.0" encoding="utf-8"?> <shap ...

  7. Android -- 贝塞尔曲线公式的推导

    1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...

  8. Android -- 贝塞尔二阶实现饿了么加入购物车效果

    1,上周我们实现了简单的三阶贝塞尔曲线效果实例,今天是使用二阶贝塞尔曲线加动画实现的加入购物车效果,在码代码过程中出现了些问题,过一下和大家来探讨探讨,先看一下效果图 2,从上面的效果来看我们基本上可 ...

  9. Android -- 贝塞尔实现水波纹动画(划重点!!)

    1,昨天看到了一个挺好的ui效果,是使用贝塞尔曲线实现的,就和大家来分享分享,还有,在写博客的时候我经常会把自己在做某种效果时的一些问题给写出来,而不是像很多文章直接就给出了解决方法,这里给大家解释一 ...

随机推荐

  1. 用jdk在cmd下运行编译java程序

    1.首先通过创建一个txt文档,将java代码写入txt文档中保存 2.将保存好的HelloWorld.txt文档重命名为HelloWorld.java文件. 3.打开windows中的"命 ...

  2. PHP 中使用 Composer

    在线安装版本: http://www.phpcomposer.com/ 这个是国内的composer网站 thinkphp5自带了composer.phar组件,如果没有安装,则需要进行安装 以下命令 ...

  3. java-6数组

    一. 请编写一个程序将一个整数转换为汉字读法字符串.比如"1123"转换为"一千一百二十三".更进一步,能否将数字表示的金额改为"汉字表达?比如将&q ...

  4. java中关于转义字符的一个bug

    在java中,你可以定义 char c = '\u4f60'; char m = '\u0045'; char e = '\u554a'; 这样的字面量,例如: System.out.println( ...

  5. elasticsearch-5.2在windows下的安装方法

    elasticsearch-5.2.1安装方法 1. 安装java 下载安装java jdk 1.7 以上 配置java环境变量 右击[我的电脑]---[属性]-----[高级系统设置]---[环境变 ...

  6. javascript小测试

     测试地址:http://toys.usvsth3m.com/javascript-under-pressure/ 在群里看到测试网站做着玩,希望你能过关,不能,且看下面答案(为了过关,不惜不够严谨) ...

  7. Qt 中QString 字符串操作:连接、组合、替换、去掉空白字符

    Qt中的字符串类 QString类 保存了16位Unicode值,提供了丰富的操作.查询和转换等函数. QString 字符串有如下几个操作符: (1) "+" 用于组合两个字符串 ...

  8. Javascript学习一

    //学习moocjs1 JavaScript-警告(alert 消息对话框) <script type="text/javascript"> var mynum = 3 ...

  9. Angular.js!(附:聊聊非原生框架项目)

    最近,为了项目接触了一个很火的前端框架Angular.js,下面就Angular做一个简介吧(大牛请绕步,只针对没有接触过angular的人). Angular.js是一款精简的前端框架,如果要追溯它 ...

  10. Docker存储驱动之AUFS简介

    简介 AUFS是曾是Docker默认的首选存储驱动.它非常稳定.有很多真实场景的部署.很强的社区支持.它有以下主要优点: 极短的容器启动时间. 有效的存储利用率. 有效的内存利用率. 虽然如此,但由于 ...