Flutter 绘制CustomPaint
2019-10-10 本文已影响0人
王俏
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Offset> _points = List<Offset>();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox obj = context.findRenderObject();
Offset _localPosition =
obj.globalToLocal(details.globalPosition);
_points = List.from(_points)..add(_localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points..add(null),
child: CustomPaint(
painter: Signature(_points),
size: Size.infinite,
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.clear),
onPressed: () => _points.clear(),
),
),
);
}
}
class Signature extends CustomPainter {
List<Offset> points;
Signature(this.points);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null) {
canvas.drawLine(points[i], points[i + 1], paint);
}
}
}
@override
bool shouldRepaint(Signature oldDelegate) => oldDelegate.points != points;
}
Flutter 的底层渲染引擎是Skia
有两个类可以帮助我们绘制画布CustomPaint和CustomPainter
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: DemoApp()));
class DemoApp extends StatelessWidget {
Widget build(BuildContext context) => Scaffold(body: Signature());
}
class Signature extends StatefulWidget {
SignatureState createState() => SignatureState();
}
class SignatureState extends State<Signature> {
List<Offset> _points = <Offset>[];
Widget build(BuildContext context) {
return GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
_points = List.from(_points)..add(localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points.add(null),
child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite),
);
}
}
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List<Offset> points;
void paint(Canvas canvas, Size size) {
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null)
canvas.drawLine(points[i], points[i + 1], paint);
}
}
bool shouldRepaint(SignaturePainter other) => other.points != points;
}
绘制圆形和方形
import 'package:flutter/material.dart';
import 'package:flutter_app/navigator/tab_navigator.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter bottomNavigationBar',
theme: new ThemeData.fallback(),
home: _MyCanvas(),
);
}
}
// Flutter
class MyCanvasPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint();
paint.color = Colors.amber;
canvas.drawCircle(Offset(100.0, 200.0), 40.0, paint);
Paint paintRect = Paint();
paintRect.color = Colors.lightBlue;
Rect rect = Rect.fromPoints(Offset(150.0, 300.0), Offset(300.0, 400.0));
canvas.drawRect(rect, paintRect);
}
bool shouldRepaint(MyCanvasPainter oldDelegate) => false;
bool shouldRebuildSemantics(MyCanvasPainter oldDelegate) => false;
}
class _MyCanvas extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomPaint(
painter: MyCanvasPainter(),
),
);
}
}
线性可拖拽进度条
import 'dart:math';
import 'package:flutter/material.dart';
import '../../res/colors.dart';
typedef ProgressChanged<double> = void Function(double value);
num degToRad(num deg) => deg * (pi / 180.0);
num radToDeg(num rad) => rad * (180.0 / pi);
class HTLinearProgressBar extends StatefulWidget {
final double width;
final double height;
double progress;
final ProgressChanged progressChanged;
HTLinearProgressBar({
Key key,
@required this.width,
@required this.height,
this.progress,
this.progressChanged,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _HTLinearProgressState();
}
class _HTLinearProgressState extends State<HTLinearProgressBar>
with SingleTickerProviderStateMixin {
AnimationController progressController;
bool isValidTouch = true;
final GlobalKey paintKey = GlobalKey();
@override
void initState() {
super.initState();
progressController =
AnimationController(duration: Duration(milliseconds: 1), vsync: this);
if (widget.progress != null) {
progressController.value = widget.progress;
} else {
progressController.value = 0;
}
progressController.addListener(() {
if (widget.progressChanged != null)
widget.progressChanged(progressController.value);
setState(() {
widget.progress = progressController.value;
});
});
}
@override
void dispose() {
progressController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final size = new Size(widget.width, widget.height);
return GestureDetector(
onPanStart: _onPanStart,
onPanUpdate: _onPanUpdate,
onPanEnd: _onPanEnd,
onTapDown: _tapDown,
// onForcePressStart: _onForcePressStart,
onForcePressEnd: _onForcePressStart,
child: Container(
alignment: FractionalOffset.center,
child: CustomPaint(
key: paintKey,
size: size,
painter: ProgressPainter(progress: widget.progress),
),
),
);
}
void _tapDown(TapDownDetails details) {
print('tap down');
RenderBox getBox = paintKey.currentContext.findRenderObject();
Offset local = getBox.globalToLocal(details.globalPosition);
final double x = local.dx;
progressController.value = x / widget.width;
}
void _onForcePressStart(ForcePressDetails details) {
// FocusScope.of(context).requestFocus(FocusNode());
RenderBox getBox = paintKey.currentContext.findRenderObject();
Offset local = getBox.globalToLocal(details.globalPosition);
final double x = local.dx;
progressController.value = x / widget.width;
}
void _onPanStart(DragStartDetails details) {
RenderBox getBox = paintKey.currentContext.findRenderObject();
Offset local = getBox.globalToLocal(details.globalPosition);
final double x = local.dx;
progressController.value = x / widget.width;
}
void _onPanUpdate(DragUpdateDetails details) {
RenderBox getBox = paintKey.currentContext.findRenderObject();
Offset local = getBox.globalToLocal(details.globalPosition);
final double x = local.dx;
progressController.value = x / widget.width;
}
void _onPanEnd(DragEndDetails details) {}
}
const double dotWidth = 20;
class ProgressPainter extends CustomPainter {
double progress;
final Color backgroundColor;
final Color forgroundColor;
final Color dotColor;
ProgressPainter({
this.backgroundColor = Colors.black12,
this.forgroundColor = Colours.app_main_transparent,
this.dotColor = Colours.app_main,
this.progress,
});
@override
void paint(Canvas canvas, Size size) {
// print('绘制进度:$progress');
// 绘制外框
Rect rect = Rect.fromPoints(Offset(0, 0), Offset(size.width, size.height));
//根据上面的矩形,构建一个圆角矩形
RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(5.0));
canvas.drawRRect(
rrect,
Paint()
..color = Colours.app_main
..strokeWidth = 1.0
..style = PaintingStyle.stroke);
// }
//绘制进度
final Gradient gradient = LinearGradient(colors: [
forgroundColor,
forgroundColor,
]);
if (progress * size.width - 1 > 0 &&
progress * size.width < size.width - 1) {
//用Rect构建一个矩形
Rect rect = Rect.fromPoints(
Offset(1, 1), Offset(progress * size.width, size.height - 1));
//根据上面的矩形,构建一个圆角矩形
RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(5.0));
Paint _paint = Paint()
..color = forgroundColor //画笔颜色
// ..strokeCap = StrokeCap.round //画笔笔触类型
..isAntiAlias = true //是否启动抗锯齿
..shader = gradient.createShader(rect)
..style = PaintingStyle.fill //绘画风格,默认为填充
..filterQuality = FilterQuality.high //颜色渲染模式的质量
..strokeWidth = 15.0; //画笔的宽度
canvas.drawRRect(rrect, _paint);
}
if (progress * size.width >= size.width - 1) {
Rect rect = Rect.fromPoints(
Offset(1, 1), Offset(size.width - 1, size.height - 1));
//根据上面的矩形,构建一个圆角矩形
RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(5.0));
Paint _paint = Paint()
..color = forgroundColor //画笔颜色
// ..strokeCap = StrokeCap.round //画笔笔触类型
..isAntiAlias = true //是否启动抗锯齿
..shader = gradient.createShader(rect)
..style = PaintingStyle.fill //绘画风格,默认为填充
..filterQuality = FilterQuality.high //颜色渲染模式的质量
..strokeWidth = 15.0; //画笔的宽度
canvas.drawRRect(rrect, _paint);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}