要想實現上圖的效果,能夠將內容分爲兩部分:canvas
二者用Stack組合bash
這裏的難點在於怎麼繪製田字格的虛線。app
已經有path_drawing的package解決這個問題,在本例中,直接複製其虛線代碼到項目中。 你們也能夠直接使用package做爲依賴less
所有源碼:ide
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'dart:ui';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Font'),
),
body: Center(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
CustomPaint(
size: Size(200, 200),
painter: Background(),
),
Text(
'字',
style: TextStyle(fontSize: 120),
)
],
),
),
);
}
}
class Background extends CustomPainter {
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
@override
void paint(Canvas canvas, Size size) {
//繪製田字格核心代碼
final paint1 = Paint()
..style = PaintingStyle.stroke
..color = Colors.black
..strokeWidth = 2;
canvas.drawLine(Offset(0, 0), Offset(size.width, 0), paint1);
canvas.drawLine(Offset(size.width, 0), Offset(size.width, size.width), paint1);
canvas.drawLine(Offset(size.width, size.width), Offset(0, size.width), paint1);
canvas.drawLine(Offset(0, size.width), Offset(0, 0), paint1);
final paint2 = Paint()
..style = PaintingStyle.stroke
..color = Colors.black
..strokeWidth = 1;
var path = Path();
path.moveTo(0, 0);
path.lineTo(size.width, size.width);
path.moveTo(0, size.width);
path.lineTo(size.width, 0);
path.moveTo(0, size.width / 2);
path.lineTo(size.width, size.width / 2);
path.moveTo(size.width / 2, 0);
path.lineTo(size.width / 2, size.width);
canvas.drawPath(dashPath(path, dashArray: CircularIntervalList([5, 5])), paint2);
}
}
//如下是path_drawing實現虛線的部分
Path dashPath(
Path source, {
@required CircularIntervalList<double> dashArray,
DashOffset dashOffset,
}) {
assert(dashArray != null);
if (source == null) {
return null;
}
dashOffset = dashOffset ?? const DashOffset.absolute(0.0);
// TODO: Is there some way to determine how much of a path would be visible today?
final Path dest = Path();
for (final PathMetric metric in source.computeMetrics()) {
double distance = dashOffset._calculate(metric.length);
bool draw = true;
while (distance < metric.length) {
final double len = dashArray.next;
if (draw) {
dest.addPath(metric.extractPath(distance, distance + len), Offset.zero);
}
distance += len;
draw = !draw;
}
}
return dest;
}
enum _DashOffsetType { Absolute, Percentage }
class DashOffset {
DashOffset.percentage(double percentage)
: _rawVal = percentage.clamp(0.0, 1.0) ?? 0.0,
_dashOffsetType = _DashOffsetType.Percentage;
const DashOffset.absolute(double start)
: _rawVal = start ?? 0.0,
_dashOffsetType = _DashOffsetType.Absolute;
final double _rawVal;
final _DashOffsetType _dashOffsetType;
double _calculate(double length) {
return _dashOffsetType == _DashOffsetType.Absolute ? _rawVal : length * _rawVal;
}
}
class CircularIntervalList<T> {
CircularIntervalList(this._vals);
final List<T> _vals;
int _idx = 0;
T get next {
if (_idx >= _vals.length) {
_idx = 0;
}
return _vals[_idx++];
}
}
複製代碼
dashPath及其後面的內容,是path_drawing實現虛線的部分,在canvas中繪製曲線也至關簡單canvas.drawPath(dashPath(path, dashArray: CircularIntervalList([5, 5])), paint2);
ui