今天。。。是一個非常重要的日子 女神節。作為一名程式員,如何向心儀的人低調而又不失逼格的表達祝福,關係到我們後半生的幸福,祝福的到位,普通朋友加個字變成女朋友,女朋友變成老婆,如果已經是老婆了,那麼這個月的零花錢又能多好幾百,想想都激動。 回到現實,作為程式員,我們當然要獨一無二,要與眾不同,要突破 ...
今天。。。是一個非常重要的日子-女神節。作為一名程式員,如何向心儀的人低調而又不失逼格的表達祝福,關係到我們後半生的幸福,祝福的到位,普通朋友加個字變成女朋友,女朋友變成老婆,如果已經是老婆了,那麼這個月的零花錢又能多好幾百,想想都激動。
回到現實,作為程式員,我們當然要獨一無二,要與眾不同,要突破天際,要能體現我們的身份,逼格滿滿,因此我們要給女神開發一個天上地下、唯吾獨尊的App絕對是你不二的選擇。
廢話不多說,No 圖 No 說話:
先來分析一波:
首先上面的效果是一直在繪製路徑,當繪製完花和葉子時在對其著色,因此這裡比較難是如何獲取路徑的點坐標,只要有點的坐標了一個個的畫出來也就實現了上面的效果。
那麼現在的重點就是如何獲取點坐標,一種方法是人工一個一個的寫,然後調整,這種方法工作量太大了,作為程式員怎麼能用這種方法呢?怎麼才可以讓程式生成這些坐標呢?
想想我們在監聽手勢(滑鼠)時是不是可以獲取到當前點的坐標,移動的時候也可以獲取到一個移動的路徑坐標,因此我們只需要在屏幕上先載入想要的圖片,然後按照圖片上的路徑移動,是不是就可以獲取到我們想要的路徑了啊。
對於任何語言來說都可以按照上面的思路來實現,下麵以目前非常火熱的Flutter來實現這個功能。
好,首先來載入一張圖片,然後監聽其手勢(滑鼠)移動事件,代碼如下:
Container(
width: 400,
height: 700,
child: GestureDetector(
onLongPressStart: (LongPressStartDetails details) {
print('${details.localPosition},');
},
onLongPressMoveUpdate: (LongPressMoveUpdateDetails details) {
print('${details.localPosition},');
},
onLongPressEnd: (LongPressEndDetails details) {
print('${details.localPosition},');
},
child: Image.asset(
'images/123.png',
fit: BoxFit.fill,
),
),
)
這裡要註意2點:
- 圖片顯示的大小最好和最終的畫布一樣大小,這樣得到的坐標不需要在轉換。
- 圖片的寬高比和畫布的寬高比要一樣。
我們把路徑輸出到控制台,後臺只需將這些坐標拷貝到應用程式即可,將這些坐標定義為數組,如下:
static final List<Offset> flowerPoints = [
Offset(182.0, 136.3),
Offset(182.7, 135.3),
Offset(183.0, 135.3),
Offset(183.3, 135.3),
...
)
點到路徑獲取到,下麵就是繪製了,先繪製紅色的花骨朵,在Flutter中繪製路徑需要繼承CustomPainter類,重寫paint
方法,繪製路徑及填充顏色代碼如下:
@override
void paint(Canvas canvas, Size size) {
//將花變為紅色
if (flowerPaths.length >= RoseData.flowerPoints.length) {
var path = Path();
for (int i = 0; i < flowerPaths.length; i++) {
if (i == 0) {
path.moveTo(flowerPaths[i].dx, flowerPaths[i].dy);
} else {
path.lineTo(flowerPaths[i].dx, flowerPaths[i].dy);
}
}
_paint.style = PaintingStyle.fill;
_paint.color = _flowerColor;
canvas.drawPath(path, _paint);
}
//繪製線
_paint.style = PaintingStyle.stroke;
_paint.color = _strokeColor;
canvas.drawPoints(PointMode.polygon, flowerPaths, _paint);
}
這裡要註意只有噹噹花骨朵所有的路徑都繪製完之後才填充顏色,而且要先填充顏色,然後繪製路線,不然路線會被填充顏色覆蓋。
要想有繪製路徑的效果,需要將點依次增加,增加動畫控制器,控制繪製路徑,代碼如下:
AnimationController _controller;
Animation<num> _animation;
@override
void initState() {
_controller = AnimationController(
duration: Duration(seconds: 10), vsync: this)
..addListener(() {
setState(() {
_flowerPaths = RoseData.flowerPoints.sublist(0, _animation.value.floor());
});
});
_animation = Tween(
begin: 0.0,
end: RoseData.flowerPoints.length)
.animate(_controller);
}
構建UI代碼如下:
@override
Widget build(BuildContext context) {
Container(
width: 400,
height: 700,
child: CustomPaint(
painter: RosePaint(_flowerPaths),
),
)
}
RosePaint是自定義的CustomPaint。效果如下:
在最終的填充上發現有一部分沒有填充上,圖中藍色點為最後一個點,所以需要在增加2個點,綠色和黃色位置的點,把未填充區域填充上。
填充點代碼如下:
static final List<Offset> flowerPoints = [
Offset(182.0, 136.3),
Offset(182.7, 135.3),
...
Offset(179.3, 301.7),
Offset(237.7, 144.7),
];
在繪製線的時候需要將這2個點去掉:
if (flowerPaths.length >= RoseData.flowerPoints.length) {
var path = Path();
for (int i = 0; i < flowerPaths.length; i++) {
if (i == 0) {
path.moveTo(flowerPaths[i].dx, flowerPaths[i].dy);
} else {
path.lineTo(flowerPaths[i].dx, flowerPaths[i].dy);
}
}
_paint.style = PaintingStyle.fill;
_paint.color = _flowerColor;
canvas.drawPath(path, _paint);
}
//繪製線
_paint.style = PaintingStyle.stroke;
_paint.color = _strokeColor;
//去掉最後2個點,最後2個點為了繪製紅色
var points = flowerPaths.sublist(0, max(0, flowerPaths.length - 2));
canvas.drawPoints(PointMode.polygon, points, _paint);
花骨朵就好了,其他的葉子和部位也是一樣的畫法,這裡就不在介紹了,由於代碼比較多,就不全貼在這裡了,如果需要可以加我微信。
今天的文章對大家是否有幫助?如果有,請在文章底部留言和點贊,以表示對我的支持,你們的留言、點贊和轉發關註是我持續更新的動力!
本人創建了一個關於Flutter的微信交流群和“技術人運營自己(吹NB)”交流群,歡迎您的加入,讓我們一起學習,一起進步,開始我們的故事。
添加微信請備註:Flutter(進Flutter交流群)、吹NB(進吹NB群)、2(都進)。我希望您備註“2”,生活不止眼前的苟且,還有詩和《遠方》。
微信:mqd_zzy