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);}@Overrideprotected 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);@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//初始化坐标系mCenterX = getWidth() / 2;mCenterY = getHeight() / 2;
}@Overrideprotected 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方法中初始化四个数据点@Overrideprotected 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方法中绘制数据点@Overrideprotected 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,所以,代码如下

 @Overrideprotected 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方法中添加控制点的绘制
@Overrideprotected 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!!!

转载于:https://www.cnblogs.com/wjtaigwh/p/6652510.html

Android -- 贝塞尔使圆渐变为桃心相关推荐

  1. android圆形贝塞尔 菜单,Android 贝塞尔曲线——圆渐变心

    大家好!我是一名执着的Android开发攻城狮,第一次写简书,没有写好的希望大家多多包涵,万事开头难,从去年开始我就想写点自己的东西,但是一直没有写下去的勇气和毅力,希望这是我一个好的习惯开始.在这我 ...

  2. android贝塞尔曲线,一文解析 Android 贝塞尔曲线

    原标题:一文解析 Android 贝塞尔曲线 相信很多同学都知道"贝塞尔曲线"这个词,我们在很多地方都能经常看到.利用"贝塞尔曲线"可以做出很多好看的UI效果, ...

  3. android自定义控件颜色渐变,Android编程实现自定义渐变颜色效果详解

    本文实例讲述了Android编程实现自定义渐变颜色效果.分享给大家供大家参考,具体如下: 你是否已经厌恶了纯色的背景呢?那好,Android提供给程序员自定义渐变颜色的接口,让我们的界面炫起来吧. x ...

  4. android 背景切换动画效果代码,关于Android shape gradient背景渐变

    百度后,发现渐变色不仅可以根据xml来实现,也可以用java代码来实现,由于目前没有那么多时间,只记录xml实现的方法:以后在记录Java实现的代码. 通过Shape gradient标签来实现 首先 ...

  5. android 底部tab效果,Android 仿微信底部渐变Tab效果

    先来看一下效果图 除了第三个的发现Tab有所差别外,其他的基本还原了微信的底部Tab渐变效果 每个Tab都是一个自定义View,根据ImageView的tint属性来实现颜色渐变效果,tint属性的使 ...

  6. android动态波浪效果,android贝塞尔曲线实现波浪效果

    本文实例为大家分享了android贝塞尔曲线实现波浪效果的具体代码,供大家参考,具体内容如下 因为手机录制gif不知道下什么软件好,所以暂时就先忽略效果图了 我在屏幕外多画了1.5个波浪,延伸至屏幕内 ...

  7. 如何在Android上使背景20%透明

    本文翻译自:How to make a background 20% transparent on Android 我如何使Textview的背景大约20%透明(不完全透明),背景中是否有颜色(即白色 ...

  8. android动态添加圆,Android开发中TextView 实现右上角跟随文本动态追加圆形红点

    在一个比较坑的需求里,一段文字右上角需要追加一个圆形红点.最右侧有个金额,红点动态随着文字移动,然后各种摆布局,一下午坑死我了.后来果断放弃.然后就想试试直接自定义view来实现这个需求. 最坑的就是 ...

  9. android波浪动画简书,Android贝塞尔曲线————波浪效果(大波浪)

    Hello大家好,很高兴又一次与大家见面,今天是农历丁酉鸡年(大年初四),现在跟大家拜年有点晚,算是拜晚年,祝大家晚年幸福. 这么快大伙都到了晚年了,Android贝塞尔曲线我也准备以一个大波浪来结束 ...

最新文章

  1. 手机将被小型机器人取代?工程院院士:人工智能技术突破是关键
  2. webmin下重启linux系统
  3. 华南赛区线上比赛安排
  4. 后量子密码芯片研究取得重大突破,论文入选ISSCC 2022和CHES 2022
  5. 1024,千家公司程序员幸福指数大比拼!最“幸福”的程序员是你吗?
  6. DEEPNORM:千层transformer...
  7. C++匿名对象生命周期静态变量函数
  8. js本地图片预览,兼容ie[6-9]、火狐、Chrome17+、Opera11+、Maxthon3
  9. 解决Nginx + PHP(FastCGI)遇到的502 Bad Gateway错误[原创]
  10. 原生App VS 移动Web App
  11. 【TSP】基于matlab模拟退火算法求解31城市旅行商问题【含Matlab源码 1148期】
  12. 机器学习模型的保存与调用
  13. 信息收集(成功就是99%的运气+1%的搜索引擎)
  14. bzoj2429- 聪明的猴子
  15. 逐点插入法-delaunay三角剖分
  16. 为什么要用VR全景?5个答案告诉你
  17. 历经一个月研究,发布两款机器人,小白就会python自己制作机器人了
  18. python实践——时间序列分析建模理论及代码实现
  19. 增量学习方法分类及近两年论文汇总
  20. 智能家居到智慧家庭-由远程操作设备到家庭智慧服务

热门文章

  1. Linux怎么互相ping通,主机+虚拟机Ubuntu+开发板互相ping通
  2. ios底部栏设计规范_UI设计:iOS 界面规范
  3. docker 端口映射 udp_Docker领路,走进压力测试的现代化 | 51上头条
  4. 【 FPGA 】FIR 滤波器之内插 FIR 滤波器(Interpolated FIR Filter)
  5. 编程语言介绍、python解释器执行代码的过程
  6. 如何保证MongoDB的安全性?
  7. vue调用百度地图API输入提示示例下拉列表一直被触发问题
  8. [2018年工作重点规划]二.max脚本加强编写能力
  9. struts2学习:配置篇值请求处理元素
  10. MAPREDUCE实践篇(2)