import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_first_station/paper/color_selector.dart'; import 'package:flutter_first_station/paper/conform_dialog.dart'; import 'model.dart'; import 'paper_app_bar.dart'; import 'stork_width_selector.dart'; class Paper extends StatefulWidget { const Paper({Key? key}) : super(key: key); @override State createState() => _PaperState(); } class _PaperState extends State { List _lines = []; // 线列表 int _activeColorIndex = 0; // 颜色激活索引 int _activeStorkWidthIndex = 0; // 线宽激活索引 // 支持的颜色 final List supportColors = [ Colors.black, Colors.red, Colors.orange, Colors.yellow, Colors.green, Colors.blue, Colors.indigo, Colors.purple, Colors.pink, Colors.grey, Colors.redAccent, Colors.orangeAccent, Colors.yellowAccent, Colors.greenAccent, Colors.blueAccent, Colors.indigoAccent, Colors.purpleAccent, Colors.pinkAccent, ]; // 支持的线粗 final List supportStorkWidths = [1, 2, 4, 6, 8, 10]; List _historyLines = []; void _back() { Line line = _lines.removeLast(); _historyLines.add(line); setState(() {}); } void _revocation() { Line line = _historyLines.removeLast(); _lines.add(line); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: PaperAppBar( onClear: _showClearDialog, onBack: _lines.isEmpty ? null : _back, onRevocation: _historyLines.isEmpty ? null : _revocation, ), body: Stack( children: [ GestureDetector( onPanStart: _onPanStart, onPanUpdate: _onPanUpdate, child: CustomPaint( painter: PaperPainter(lines: _lines), child: ConstrainedBox(constraints: const BoxConstraints.expand()), ), ), Positioned( bottom: 0, width: MediaQuery.of(context).size.width, child: Row( children: [ Expanded( child: ColorSelector( supportColors: supportColors, activeIndex: _activeColorIndex, onSelect: _onSelectColor, ), ), StorkWidthSelector( supportStorkWidths: supportStorkWidths, color: supportColors[_activeColorIndex], activeIndex: _activeStorkWidthIndex, onSelect: _onSelectStorkWidth, ), ], ), ), ], ), ); } void _showClearDialog() { String msg = "您的当前操作会清空绘制内容,是否确定删除!"; showDialog( context: context, builder: (ctx) => ConformDialog( title: '清空提示', conformText: '确定', msg: msg, onConform: _clear, )); } void _clear() { _lines.clear(); Navigator.of(context).pop(); setState(() {}); } void _onPanStart(DragStartDetails details) { _lines.add(Line( points: [details.localPosition], strokeWidth: supportStorkWidths[_activeStorkWidthIndex], color: supportColors[_activeColorIndex], )); } void _onPanUpdate(DragUpdateDetails details) { Offset point = details.localPosition; double distance = (_lines.last.points.last - point).distance; if (distance > 5) { _lines.last.points.add(details.localPosition); setState(() {}); } } void _onSelectStorkWidth(int index) { if (index != _activeStorkWidthIndex) { setState(() { _activeStorkWidthIndex = index; }); } } void _onSelectColor(int index) { if (index != _activeColorIndex) { setState(() { _activeColorIndex = index; }); } } } class PaperPainter extends CustomPainter { PaperPainter({ required this.lines, }) { _paint = Paint() ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round; } late Paint _paint; final List lines; @override void paint(Canvas canvas, Size size) { for (int i = 0; i < lines.length; i++) { drawLine(canvas, lines[i]); } } ///根据点位绘制线 void drawLine(Canvas canvas, Line line) { _paint.color = line.color; _paint.strokeWidth = line.strokeWidth; canvas.drawPoints(PointMode.points, line.points, _paint); } @override bool shouldRepaint(CustomPainter oldDelegate) => true; }