Flutter学习笔记

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;
  }
}

上一篇下一篇

猜你喜欢

热点阅读