创建工具类MyUtil
public class MyUtil {public static float circle = (float) (2 * Math.PI);public static int rgba(int r, int g, int b, int a) {return Color.argb(a, r, g, b);}public static int randomInt(int min, int max) {return (int) Math.floor(Math.random() * (max - min + 1)) + min;}public static float random(float min, float max) {return (float) (Math.random() * (max - min) + min);}//产生随机的argb颜色public static int randomrgba(int rmin, int rmax, int gmin, int gmax, int bmin, int bmax, int a) {int r = Math.round(random(rmin, rmax));int g = Math.round(random(gmin, gmax));int b = Math.round(random(bmin, bmax));int limit = 5;if (Math.abs(r - g) <= limit && Math.abs(g - b) <= limit && Math.abs(b - r) <= limit) {return rgba(rmin, rmax, gmin, gmax);} else {return rgba(r, g, b, a);}}//角度转弧度public static float degrad(float angle) {return circle / 360 * angle;}}
创建工具类Point
public class Point {public int x;public int y;public Point(int x, int y) {this.x = x;this.y = y;}//旋转public Point rotate(float theta) {int x = this.x;int y = this.y;this.x = (int) (Math.cos(theta) * x - Math.sin(theta) * y);this.y = (int) (Math.sin(theta) * x + Math.cos(theta) * y);return this;}//乘以一个常数public Point mult(float f) {this.x *= f;this.y *= f;return this;}//复制public Point clone() {return new Point(this.x, this.y);}//该点与圆心距离public float length() {return (float) Math.sqrt(this.x * this.x + this.y * this.y);}//向量相减public Point subtract(Point p) {this.x -= p.x;this.y -= p.y;return this;}//向量相加public Point add(Point p) {this.x += p.x;this.y += p.y;return this;}public Point set(int x, int y) {this.x = x;this.y = y;return this;}}
public class Petal {private float stretchA;//第一个控制点延长线倍数private float stretchB;//第二个控制点延长线倍数private float startAngle;//起始旋转角,用于确定第一个端点private float angle;//两条线之间夹角,由起始旋转角和夹角可以确定第二个端点private int radius = 2;//花芯的半径private float growFactor;//增长因子,花瓣是有开放的动画效果,这个参数决定花瓣展开速度private int color;//花瓣颜色private boolean isFinished = false;//花瓣是否绽放完成private Path path = new Path();//用于保存三次贝塞尔曲线private Paint paint = new Paint();//画笔//构造函数,由花朵类调用public Petal(float stretchA, float stretchB, float startAngle, float angle, int color, float growFactor) {this.stretchA = stretchA;this.stretchB = stretchB;this.startAngle = startAngle;this.angle = angle;this.color = color;this.growFactor = growFactor;paint.setColor(color);}//用于渲染花瓣,通过不断更改半径使得花瓣越来越大public void render(Point p, int radius, Canvas canvas) {if (this.radius <= radius) {this.radius += growFactor; // / 10;} else {isFinished = true;}this.draw(p, canvas);}//绘制花瓣,参数p是花芯的圆心的坐标private void draw(Point p, Canvas canvas) {if (!isFinished) {path = new Path();//将向量(0,radius)旋转起始角度,第一个控制点根据这个旋转后的向量计算Point t = new Point(0, this.radius).rotate(MyUtil.degrad(this.startAngle));//第一个端点,为了保证圆心不会随着radius增大而变大这里固定为3Point v1 = new Point(0, 3).rotate(MyUtil.degrad(this.startAngle));//第二个端点Point v2 = t.clone().rotate(MyUtil.degrad(this.angle));//延长线,分别确定两个控制点Point v3 = t.clone().mult(this.stretchA);Point v4 = v2.clone().mult(this.stretchB);//由于圆心在p点,因此,每个点要加圆心坐标点v1.add(p);v2.add(p);v3.add(p);v4.add(p);path.moveTo(v1.x, v1.y);//参数分别是:第一个控制点,第二个控制点,终点path.cubicTo(v3.x, v3.y, v4.x, v4.y, v2.x, v2.y);}canvas.drawPath(path, paint);}
}
public class Garden {//创建一个随机的花朵public Bloom createRandomBloom(int x, int y) {//创建一个随机的花朵半径int radius = MyUtil.randomInt(Options.minBloomRadius, Options.maxBloomRadius);//创建一个随机的花朵颜色int color = MyUtil.randomrgba(Options.minRedColor, Options.maxRedColor, Options.minGreenColor, Options.maxGreenColor, Options.minBlueColor, Options.maxBlueColor, Options.opacity);//创建随机的花朵中花瓣个数int petalCount = MyUtil.randomInt(Options.minPetalCount, Options.maxPetalCount);return createBloom(x, y, radius, color, petalCount);}//创建花朵public Bloom createBloom(int x, int y, int radius, int color, int petalCount) {return new Bloom(new Point(x, y), radius, color, petalCount);}static class Options {//用于控制产生随机花瓣个数范围public static int minPetalCount = 8;public static int maxPetalCount = 15;//用于控制产生延长线倍数范围public static float minPetalStretch = 2f;public static float maxPetalStretch = 3.5f;//用于控制产生随机增长因子范围,增长因子决定花瓣绽放速度public static float minGrowFactor = 1f;public static float maxGrowFactor = 1.1f;//用于控制产生花朵半径随机数范围public static int minBloomRadius = 8;public static int maxBloomRadius = 10;//用于产生随机颜色public static int minRedColor = 128;public static int maxRedColor = 255;public static int minGreenColor = 0;public static int maxGreenColor = 128;public static int minBlueColor = 0;public static int maxBlueColor = 128;//花瓣的透明度public static int opacity = 50;//0.1}
}
public class Bloom {private int color;//整个花朵的颜色private Point point;//花芯圆心private int radius; //花芯半径private ArrayList<Petal> petals;//用于保存花瓣public Point getPoint() {return point;}public Bloom(Point point, int radius, int color, int petalCount) {this.point = point;this.radius = radius;this.color = color;petals = new ArrayList<>(petalCount);float angle = 360f / petalCount;int startAngle = MyUtil.randomInt(0, 90);for (int i = 0; i < petalCount; i++) {//随机产生第一个控制点的拉伸倍数float stretchA = MyUtil.random(Garden.Options.minPetalStretch, Garden.Options.maxPetalStretch);//随机产生第二个控制地的拉伸倍数float stretchB = MyUtil.random(Garden.Options.minPetalStretch, Garden.Options.maxPetalStretch);//计算每个花瓣的起始角度int beginAngle = startAngle + (int) (i * angle);//随机产生每个花瓣的增长因子(即绽放速度)float growFactor = MyUtil.random(Garden.Options.minGrowFactor, Garden.Options.maxGrowFactor);//创建一个花瓣,并添加到花瓣列表中this.petals.add(new Petal(stretchA, stretchB, beginAngle, angle, color, growFactor));}}//绘制花朵public void draw(Canvas canvas) {Petal p;for (int i = 0; i < this.petals.size(); i++) {p = petals.get(i);//渲染每朵花朵p.render(point, this.radius, canvas);}}public int getColor() {return color;}}自定义view
public class HeartView extends SurfaceView implements SurfaceHolder.Callback {SurfaceHolder surfaceHolder;int offsetX;int offsetY;private Garden garden;private int width;private int height;private Paint backgroundPaint;private boolean isDrawing = false;private Bitmap bm;private Canvas canvas;private int heartRadio = 1;public HeartView(Context context) {super(context);init();}public HeartView(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {surfaceHolder = getHolder();surfaceHolder.addCallback(this);garden = new Garden();backgroundPaint = new Paint();backgroundPaint.setColor(Color.rgb(0xff, 0xff, 0xe0));}ArrayList<Bloom> blooms = new ArrayList<>();public Point getHeartPoint(float angle) {float t = (float) (angle / Math.PI);float x = (float) (heartRadio * (16 * Math.pow(Math.sin(t), 3)));float y = (float) (-heartRadio * (13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t)));return new Point(offsetX + (int) x, offsetY + (int) y);}//绘制列表里所有的花朵private void drawHeart() {canvas.drawRect(0, 0, width, height, backgroundPaint);for (Bloom b : blooms) {b.draw(canvas);}Canvas c = surfaceHolder.lockCanvas();try {c.drawBitmap(bm, 0, 0, null);}catch (Exception e){e.printStackTrace();}surfaceHolder.unlockCanvasAndPost(c);}public void reDraw() {blooms.clear();drawOnNewThread();}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);}//开启一个新线程绘制private void drawOnNewThread() {new Thread() {@Overridepublic void run() {if (isDrawing) return;isDrawing = true;float angle = 10;while (true) {Bloom bloom = getBloom(angle);if (bloom != null) {blooms.add(bloom);}if (angle >= 30) {break;} else {angle += 0.2;}drawHeart();try {sleep(20);} catch (InterruptedException e) {e.printStackTrace();}}isDrawing = false;}}.start();}private Bloom getBloom(float angle) {Point p = getHeartPoint(angle);boolean draw = true;/**循环比较新的坐标位置是否可以创建花朵,* 为了防止花朵太密集* */for (int i = 0; i < blooms.size(); i++) {Bloom b = blooms.get(i);Point bp = b.getPoint();float distance = (float) Math.sqrt(Math.pow(p.x - bp.x, 2) + Math.pow(p.y - bp.y, 2));if (distance < Garden.Options.maxBloomRadius * 1.5) {draw = false;break;}}//如果位置间距满足要求,就在该位置创建花朵并将花朵放入列表if (draw) {Bloom bloom = garden.createRandomBloom(p.x, p.y);return bloom;}return null;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {this.width = width;this.height = height;//我的手机宽度像素是1080,发现参数设置为30比较合适,这里根据不同的宽度动态调整参数heartRadio = width * 30 / 1080;offsetX = width / 2;offsetY = height / 2 - 55;bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);canvas = new Canvas(bm);drawOnNewThread();}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}
}

浪漫表白心形花瓣动图相关推荐

  1. 利用MATLAB绘制各种表白心形-跳动心形

    利用MATLAB绘制各种表白心形♥ 跳动三维心形 表白情人节必备 面向工科屌丝男 固定心形的各种画法见下面连接 链接: https://blog.csdn.net/weixin_44044161/ar ...

  2. 利用MATLAB绘制各种表白心形-固定心形

    利用MATLAB绘制各种表白心形♥ 第一种 固定三维心形 f=@(x,y,z)(x.^2+ (9./4).*y.^2 + z.^2 - 1).^3 -x.^2.*z.^3 - (9./80).*y.^ ...

  3. python浪漫代码-Python打造浪漫的心形,助你情人节表白成功!

    Python是一种面向他人进行的说明型编程方法,其源代码与说明器CPython遵守GPL协议,语法简洁清晰.那么,我们用少量的Python代码能做哪些有趣的东西?让小编告诉你. 一.编写浪漫的心型 1 ...

  4. 一条python 语句绘制浪漫的心形图案-----附解释(七夕专供)

    文章目录 七夕也要好好学习 列表表达式解释 小结 列表推导式 [* for i in *] 条件赋值语句 value = a if condition else b 七夕也要好好学习 心形曲线函数1( ...

  5. 用笛卡尔公式绘图表白心形

    实现效果: 代码段: package 爱的告白;//AWT技术画出游戏主窗口主要是进行窗口一些属性的设置,包括大小,可显示度,位置,和窗口监听,这些都是Java的内部类. import java.aw ...

  6. 基于51单片机的心形流水灯

    心形流水灯套件 1  设计目的 (1)掌握单片机芯片AT89C51的基本功能和使用. (2)熟悉Proteus仿真软件的使用,了解各元件的功能及作用. (3)了解音乐的基本知识. (4)提高数字电子电 ...

  7. 心形函数用计算机怎么画,怎么用几何画板画爱心,真神奇!

    原标题:怎么用几何画板画爱心,真神奇! 爱心的形状除了能用一些普通的画图工具绘制,还可以借助强大的几何绘图软件--几何画板,千万不要以为几何画板只能画一些基本几何图形,其实它的功能强大着呢. 其实在使 ...

  8. Word文档中插入心形特殊符号

    爱心符号怎么打 ? 1.打开Word文档,这里主要是方便复制心形符号  如图 2.在文档的菜单栏里点击"插入" 如图 3.然后点击"符号"  如图 4.在打开的 ...

  9. Python pyglet 自制3D引擎入门(二) -- 绘制立体心形,动画和相机控制

    Python作为目前较广泛的编程语言, 用于制作3D游戏可谓得心应手.本文讲解使用Python pyglet库自制简易3D引擎的方法技巧. 上篇:Python pyglet 自制3D引擎入门(一) – ...

最新文章

  1. 怎么修改网页服务器数据库连接,如何修改网页服务器数据库连接
  2. mysql druid 多数据源_SpringBoot使用阿里数据库连接池Druid以及多数据源配置
  3. python语言入门pdf-Python语言及其应用 中文pdf完整版[13MB]
  4. .Net Compact Framework 小技巧(1)
  5. adapt和adopt的区别_“适应”是“ adapt ”还是“ adopt ”?看完你就会了
  6. TSubclassOf
  7. 关于Python的一切:2018年,你读这8本书就够了
  8. autowired注入jar中的依赖_springboot项目中调用jar包中的类时报错 — 没有注入类
  9. 问题:动态变换video标签source的src不起作用
  10. Ant的使用 - 简单介绍
  11. 微信公号“架构师之路”学习笔记(四)-分布式ID生成算法(应用场景、uuid/guid、snowflake算法)
  12. ad如何绘制拼版_ad 拼板
  13. ASCII码对照表(emoji表情符号)
  14. 大学课程 | 《计算机系统结构》详细知识点总结
  15. JMP数据清洗之“拆分” — 快速实现一列拆分为多列
  16. java文件名特殊字符_文件名不能包含哪些特殊字符
  17. 2021山东上半年软考时间已定!!!
  18. Hadoop之Lzo压缩配置
  19. 图中连通块的个数:并查集
  20. 比尔盖茨、贝佐斯、扎克伯格-硅谷大佬的书单

热门文章

  1. php实现sftp上传文件,PHP-sftp文件上传
  2. 输入数字1-7中的任意一个数,若输入1,则输出 星期一,一次类推,输入7,则输出星期日。(使用switch语句)
  3. VSCode配置python调试环境
  4. 编译原理——短语、直接短语、句柄
  5. 关于PS降噪的两种方法
  6. Vulkan系列教程—VMA教程(一)—快速上手VMA
  7. VMA On K1 Powerlinux
  8. linux监测本机udp发动情况,Linux 下 TCP/UDP 端口测试及验证方法说明
  9. Codimd接入单点登录
  10. 多普达、HTC的来龙去脉(手机开发)