整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          程序員“520”專屬表達方式

          者:huachao1001

          博客:https://juejin.im/entry/576b6430816dfa0055bdaf71

          碼仔,你知道今天是什么日子嗎?

          嘿嘿~當然知道!5.2.0~

          喲~ 這也知道!

          那是~~還能給你show一段!

          看好了!

          幾年前,看到過有個牛人用HTML5繪制了浪漫的愛心表白動畫(HTML5的鏈接請查看原文~),發現原來程序員也是可以很浪……漫…..的……

          那么在Android怎么打造如此這個效果呢?參考了一下前面HTML5的算法,在Android中實現了類似的效果。(似不似很膩害)

          先貼上最終效果圖:

          生成心形線

          心形線的表達式可以參考:桃心線。里面對桃心線的表達式解析的挺好。可以通過使用極坐標的方式,傳入角度和距離(常量)計算出對應的坐標點。其中距離是常量值,不需改變,變化的是角度。

          桃心線極坐標方程式為:

          x = 16×sin3αy = 13×cosα ? 5×cos2α ? 2×cos3α ? cos4α

          如果生成的桃心線不夠大,可以吧x、y乘以一個常數,使之變大。考慮到大部分人都不愿去研究具體的數學問題,我們直接把前面HTML5的JS代碼直接翻譯成Java代碼就好。代碼如下:

          public Point getHeartPoint(float angle) {
          float t = (float) (angle / Math.PI);
          float x = (float) (19.5 * (16 * Math.pow(Math.sin(t), 3)));
          float y = (float) (-20 * (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);
          }

          其中offsetX和offsetY是偏移量。使用偏移量主要是為了能讓心形線處于中央。offsetX和offsetY的值分別為:

          offsetX = width / 2;
          offsetY = height / 2 - 55;

          通過這個函數,我們可以將角度從(0,180)變化,不斷取點并畫點將這個心形線顯示出來。好了,我們自定義一個View,然后把這個心形線畫出來吧!

          @Override
          protected void onDraw(Canvas canvas) {
          float angle = 10;
          while (angle < 180) {
          Point p = getHeartPoint(angle);
          canvas.drawPoint(p.x, p.y, paint);
          angle = angle + 0.02f;
          }
          }

          運行結果如下:

          繪制花瓣原理

          我們想要的并不是簡單繪制一個桃心線,要的是將花朵在桃心線上擺放。

          首先,得要知道怎么繪制花朵,而花朵是由一個個花瓣組成。因此繪制花朵的核心是繪制花瓣。

          繪制花瓣的原理是:3次貝塞爾曲線。三次貝塞爾曲線是由兩個端點和兩個控制點決定。

          假設花芯是一個圓,有n個花瓣,那么兩個端點與花芯的圓心連線之間的夾角即為360/n。因此可以根據花瓣數量和花芯半徑確定每個花瓣的位置。將兩個端點與花芯的圓心連線的延長線分別確定另外兩個控制點。通過隨機生成花芯半徑、每個花瓣的起始角以及隨機確定延長線得到兩個控制點,可以繪制一個隨機的花朵。

          參數的改變如下圖所示:

          將花朵繪制到桃心線上

          一大波代碼來襲

          首先定義花瓣類Petal:

          package com.hc.testheart;

          import android.graphics.Canvas;
          import android.graphics.Paint;
          import android.graphics.Path;

          /**
          * Package com.example.administrator.testrecyclerview
          * Created by HuaChao on 2016/5/25.
          */
          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增大而變大這里固定為3
          Point 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);
          }
          }

          花瓣類是最重要的類,因為真正繪制在屏幕上的是一個個小花瓣。每個花朵包含一系列花瓣,花朵類Bloom如下:

          package com.hc.testheart;
          import android.graphics.Canvas;
          import java.util.ArrayList;

          /**
          * Package com.example.administrator.testrecyclerview
          * Created by HuaChao on 2016/5/25.
          */
          public class Bloom {
          private int color;
          private Point point;
          private int radius;
          private ArrayList 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;
          }
          }

          接下來是花園類Garden,主要用于創建花朵以及一些相關配置:

          package com.hc.testheart;
          import java.util.ArrayList;

          /**
          * Package com.example.administrator.testrecyclerview
          * Created by HuaChao on 2016/5/24.
          */
          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;
          }
          }

          考慮到刷新的比較頻繁,選擇使用SurfaceView作為顯示視圖。

          自定義一個HeartView繼承SurfaceView。

          代碼如下:

          package com.hc.testheart;

          import android.content.Context;
          import android.graphics.Bitmap;
          import android.graphics.Canvas;
          import android.graphics.Color;
          import android.graphics.Paint;
          import android.util.AttributeSet;
          import android.view.SurfaceHolder;
          import android.view.SurfaceView;

          import java.util.ArrayList;

          /**
          * Package com.hc.testheart
          * Created by HuaChao on 2016/5/25.
          */
          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 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;
          c.drawBitmap(bm, 0, 0, );
          surfaceHolder.unlockCanvasAndPost(c);
          }

          public void reDraw {
          blooms.clear;
          drawOnNewThread;
          }

          @Override
          public void draw(Canvas canvas) {
          super.draw(canvas);
          }

          private void drawOnNewThread {
          new Thread {
          @Override
          public void run {
          if (isDrawing) return;
          isDrawing = true;
          float angle = 10;
          while (true) {
          Bloom bloom = getBloom(angle);
          if (bloom != ) {
          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 ;
          }

          @Override
          public void surfaceCreated(SurfaceHolder holder) {
          }

          @Override
          public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
          this.width = width;
          this.height = height;
          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;
          }

          @Override
          public void surfaceDestroyed(SurfaceHolder holder) {
          }
          }

          還有兩個比較重要的工具類

          Point.java保存點信息,或者說是向量信息。包含向量的基本運算。

          package com.hc.testheart;

          /**
          * Package com.hc.testheart
          * Created by HuaChao on 2016/5/25.
          */
          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;
          }
          }

          工具類MyUtil.java主要是產生隨機數、顏色等

          package com.hc.testheart;

          import android.graphics.Color;

          /**
          * Package com.example.administrator.testrecyclerview
          * Created by HuaChao on 2016/5/25.
          */
          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;
          }
          }

          好了,目前為止,就可以得到上面的效果了。

          碼仔只能幫你到這里了!

          (源碼地址請查看原文~)

          近期文章:

          • 送三個福利(專屬)

          • 今天我把APP的編譯速度縮短了近5倍

          • 從XML變成View,它經歷了什么?

          今日問題:

          你有沒有寫過浪漫的程序?

          快來碼仔社群解鎖新姿勢吧!社群升級:Max你的學習效率

          ,就關注我。

          人狠,話不多,直接進入主題;

          C程序員

          簡單粗暴“我愛你”

          #include <stdio.h>
          #include <stdlib.h>
          
          int main()
          {
              int i,k;
              printf("我我我我我我  愛愛愛愛愛愛  你你你你你你你\n");
              for(i=0;i<3;i++)
              printf("我                      愛  你          你\n");
              printf("我我我我我我  愛愛愛愛愛愛  你          你\n");
              for(k=0;k<3;k++)
              printf("          我  愛            你          你\n");
              printf("我我我我我我  愛愛愛愛愛愛  你你你你你你你\n");
              return 0;
          }

          效果

          JAVA程序員

          我比C呆瓜浪漫點:

          代碼太長,見鏈接:

          https://blog.csdn.net/qq_42185999/article/details/88386998

          專屬java程序員的浪漫

          Android 開發程序員

          我要在你掌心里畫一條優美的弧線:

          源碼:https://www.jianshu.com/p/329339c58dd5

          安卓傻瓜的浪漫表白,可以自定義加字

          前端開發者

          心動態生成,右側時間實時更新,左邊可以作為表白的語句,一個字一個字顯現。

          源碼(算是幫別人免費推薦了一波,我心痛):https://www.html5tricks.com/html5-heart-animation.html

          后臺開發者

          我愛你,結束。



          歡迎關注技術閣,發布有趣的科技資訊,分享有料的技術干貨。

          記得關注哦,謝謝!

          天是2019年的第一個情人節!,是的你沒聽錯,是情人節到了,還在辦公室加班的你還在加班嗎?



          是不是樂此不疲 ?



          還在趕項目進度而 忘記吃飯甚至忘記給女朋友驚喜 的你,知道老板已經已經在為情人節狂歡了嗎?



          好了,這些都沒有關系,誰叫你是程序猿呢,程序猿的情人節就要跟別人不一樣!

          程序猿要是有喜歡的人(沒有也假設有),那各種表白送情意的招兒那還少嗎?

          什么?一臉懵逼? 下面還是給大家普及普及吧

          小編和廣大程序猿一樣,一直認為情人節最好的禮物就是...

          送你一桶代碼!~~

          沒錯,你沒看錯的。

          | Java 程序猿 |



          在生命結束之前,每天都會愛你多一點。

          | C 程序猿 |



          without u(沒有了你),我再也不能對 the world(這個世界) say hello!

          | 高級的程序猿 |



          兩隔的世界;

          無名的信件;

          短暫的停留;

          長久的記憶;

          說這么多,只想告訴你:我想你了。

          | Python 程序猿 |



          山無陵,江水為竭,冬雷震震,夏雨雪,天地合,乃敢與君絕!

          | Javascript 程序猿 |



          春風十里不如你!

          還有... ~~~~!

          | 搞 DBA的 |



          把你的心、我的心,串一串,串一株幸運草,串一個同心圓...

          | 搞運維的 |



          每天只想對你道下晚安:做個好夢,my 甜心!

          | 搞前端的 | 硬是用Html5 整出了一個3D表白圖:



          ~~!!! 還是搞前端的有優勢啊

          | 后端程序猿 | 表示不服,祭出了這段代碼:



          也不知道是什么意思,反正小編粘貼到 Shell 客戶端后就變成了這樣:



          | 搞架構的 |



          都 三四十的人了,不敢亂表白呀 `_`!!,很有責任心呢,實在是好榜樣。



          | 搞臨時工的 |



          俺也不會啥代碼的,就送幾個鉆戒吧..





          小編呢,也偷偷找了一個有個性的詩句,可以借鑒采納

          我能抽象出整個世界...

          但是我不能抽象出你...

          因為你在我心中是那么的具體...

          所以我的世界并不完整...

          我可以重載甚至覆蓋這個世界里的任何一種方法...

          但是我卻不能重載對你的思念...

          也許命中注定了 你在我的世界里永遠的烙上了靜態的屬性...

          而我不慎調用了愛你這個方法...

          當我義無返顧的把自己作為參數傳進這個方法時...

          我才發現愛上你是一個死循環...

          它不停的返回對你的思念壓入我心里的堆棧...

          在這無盡的黑夜中...

          我的內存里已經再也裝不下別人...



          謹以此篇送給還在猶豫的你,不管結果如何努力過就好,祝愿天下有情猿終有眷屬!

          本文大多內容摘自互聯網,如有雷同請勿噴勿念,大家開心就好。


          主站蜘蛛池模板: 国产香蕉一区二区三区在线视频 | 中文字幕人妻丝袜乱一区三区| 99精品国产高清一区二区三区 | 成人精品视频一区二区| 中文字幕无码免费久久9一区9| 人妻无码视频一区二区三区| 日韩一区二区a片免费观看| 国产情侣一区二区| 亚洲一区无码中文字幕乱码| 91久久精品国产免费一区| 日韩一区二区超清视频| 亚洲国产日韩一区高清在线| 日韩综合无码一区二区| 日本欧洲视频一区| 精品无人乱码一区二区三区| 在线观看精品一区| 国产激情з∠视频一区二区| 精品动漫一区二区无遮挡| 无码人妻一区二区三区在线水卜樱 | 久久精品视频一区二区三区| 色窝窝免费一区二区三区| 精品一区二区无码AV| 国产精品综合一区二区| 国产激情一区二区三区 | 国产成人一区二区精品非洲| 亚洲av无码一区二区三区网站| 中文字幕一区日韩精品| 国产午夜福利精品一区二区三区 | 国产香蕉一区二区精品视频| 精品一区二区三区四区在线播放 | 日韩在线视频不卡一区二区三区| 无码日韩人妻AV一区二区三区| 无码人妻精品一区二区三区久久| 亚洲AV无码国产精品永久一区| 国产精品 一区 在线| 久久婷婷久久一区二区三区| 亚洲AV无码一区二区三区鸳鸯影院| 久久影院亚洲一区| 国内精品一区二区三区在线观看| 亚洲乱码国产一区三区| 国产福利在线观看一区二区|