由於工作中專案需求,需要將H5轉換為Flutter程式碼。
其中的斑馬紋背景需要根據介面返回的顏色來渲染,所以不能只是圖片形式,無法通過decoration屬性設定圖片背景板。
樓主這邊想到的方法就是通過 實現一個canvas繪製斑馬紋類。使用Stack佈局,將斑馬紋放在下方作為背景板,需要展示的內容在上方。
實現 「斑馬紋」背景(需要變換顏色)
文章主要分為 效果圖、實現思維、程式碼、計算過程解釋。希望對大家有所幫助
使用CustomPaint(size: Size(width, height), painter: 畫筆)
CustomPaint(
size: Size(widget.width, widget.height),
painter: 畫筆,
)
繼承 CustomPainter類,實現paint(Canvas canvas, Size size)方法,根據 寬度、高度、畫筆寬度、間距 計算出各個點位。使用canvas. drawLine方法 繪製出斑馬紋。
@override
void paint(Canvas canvas, Size size) {
…
canvas. drawLine();
}
2.82 = 2倍根號2
1.41 = 根號二
填充個數= 最大高度 / (畫筆寬度1.41+間距) 向上取整。(從0, 0開始,左側會露出空位,所以需要填充)
條紋個數 = 寬度/(畫筆寬度1.41+間距) 向上取整。
(x軸y軸) 偏移量 =畫筆寬度 / 2.82 (畫筆起始點、結束點會露出一小節,需要計算x,y偏移量。將左上角x,y減去偏移量,右下角x,y加上偏移量,補充此部分)
起點座標 =((畫筆寬度1.41+間距) * 條紋index – 偏移量,– 偏移量)
終點座標 =((畫筆寬度1.41+間距) * 條紋index - 偏移量+高度, 高度+偏移量)
由於畫筆繪製的是直角的,所以作為背景板會超出,需要裁剪掉四個角。使用
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: xxx
)
使用Stack佈局,實現斑馬紋在下方作為背景板,需要展示的內容在上方
Stack(
children: [
buildZebraBack(…),
需要展示的內容
]
)
Stack(
children: [
Positioned(
child: ZebraStripesBack(
width: 335,
height: 44,
lineWidth: 10,
spacing: 10,
borderRaduis: 10,
lineColor: Colors.blue),
top: 0,
left: 0,
),
Container(
width: 335,
height: 44,
alignment: Alignment.center,
padding: EdgeInsets.only(
top: 10,
left: 12,
bottom: 10,
right: 12),
child: Text(
"英語",
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 14.sp,
fontWeight: FontWeight.w500),
)
)
]
)
import 'dart:math';
import 'package:flutter/material.dart';
// 斑馬紋具體實現類
class ZebraStripesBack extends StatefulWidget {
ZebraStripesBack({
this.width: 0,
this.height: 0,
this.spacing: 4,
this.lineWidth: 4,
this.lineColor: Colors.transparent,
this.borderRaduis: 0,
});
final double width; // 容器寬度
final double height; // 容器高度
final double lineWidth; // 斑馬紋寬度
final double spacing; // 間距
final double borderRaduis; // 容器圓角
final Color lineColor; // 斑馬紋顏色
@override
State<StatefulWidget> createState() => _ZebraStripesBackState();
}
class _ZebraStripesBackState extends State<ZebraStripesBack> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(widget.borderRaduis)),
child: CustomPaint(
size: Size(widget.width, widget.height),
painter: _ZebraStripesBackPainter(
maxWidth: widget.width,
maxHeight: widget.height,
spacing: widget.spacing,
lineWidth: widget.lineWidth,
lineColor: widget.lineColor,
borderRaduis: widget.borderRaduis,
),
));
}
}
class _ZebraStripesBackPainter extends CustomPainter {
_ZebraStripesBackPainter({
this.maxWidth: 0,
this.maxHeight: 0,
this.spacing: 4,
this.lineWidth: 4,
this.lineColor: Colors.black12,
this.borderRaduis: 0,
});
final double maxWidth;
final double maxHeight;
final double spacing;
final double lineWidth;
final Color lineColor;
final double borderRaduis;
@override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..isAntiAlias = true
..style = PaintingStyle.fill
..color = lineColor
..strokeWidth = lineWidth;
int number = 0; // 個數
int fillNumber = 0; // 填充個數
double lineAndSpace = lineWidth *1.41 + spacing; // 單個條紋寬 + 間距寬
if (lineWidth > 0) {
number = (maxWidth / lineAndSpace).ceil();
fillNumber = (maxHeight / lineAndSpace).ceil(); // 填充個數
}
double deviation = lineWidth / 2.82; // x y軸偏移量 = width / 2倍根號2
for (int i = -fillNumber; i < number; i++) {
var left = lineAndSpace * i - deviation;
double dx = left;
double dy = -deviation;
double dx1 = left + maxHeight;
double dy1 = maxHeight + deviation;
canvas.drawLine(
Offset(dx, dy),
Offset(dx1, dy1),
paint,
);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}