1

我正在尝试编写一个绘图应用程序,用户可以在其中选择不同的笔颜色并绘制彩色绘图。我创建了一个 PointsGroup 类,它存储偏移列表和相关颜色。在 GestureDetector 的 onPanUpdate 中,PointsGroup 被附加到 PointsGroup 列表并传递给 SignaturePainter。

但是画的有点慢,笔一动就画不出来。

你可以看视频https://free.hubcap.video/v/LtOqoEj9H0dY9F9xC_jSst9HT3tSOJlTi

    import 'package:flutter/material.dart';

List<Color> colorList = [
  Colors.indigo,
  Colors.blue,
  Colors.green,
  Colors.yellow,
  Colors.orange,
  Colors.red
];

void main() => runApp(MaterialApp(
      home: HomePage(),
      debugShowCheckedModeBanner: false,
    ));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<Offset> _points = <Offset>[];
  List<Offset> _setPoints = <Offset>[];
  List<PointsGroup> _ptsGroupList = <PointsGroup>[];
  int startIndex;
  int endIndex;

  @override
  void initState() {
    ColorChoser.penColor = Colors.black;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          GestureDetector(
            onPanStart: (details) {
              setState(() {
                _points.clear();
                startIndex = _ptsGroupList.length;
                ColorChoser.showColorSelector = false;
              });
            },
            onPanUpdate: (DragUpdateDetails details) {
              setState(() {
                RenderBox object = context.findRenderObject();
                Offset _localPosition =
                    object.globalToLocal(details.globalPosition);
                _points = new List.from(_points)..add(_localPosition);
                _setPoints = new List.from(_points);
                _ptsGroupList.add(new PointsGroup(
                    setPoints: _setPoints, setColor: ColorChoser.penColor));
              });
            },
            onPanEnd: (DragEndDetails details) {
              setState(() {
                _points.add(null);
                ColorChoser.showColorSelector = true;
                endIndex = _ptsGroupList.length;
                if (startIndex < endIndex) {
                  _ptsGroupList.replaceRange(
                      startIndex, endIndex - 1, [_ptsGroupList.removeLast()]);
                }
              });
            },
            child: CustomPaint(
              painter: SignaturePainter(grpPointsList: _ptsGroupList),
              size: Size.infinite,
            ),
          ),
          ColorChoser(),
        ],
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.undo),
          onPressed: () {
            setState(() {
              if (_ptsGroupList.length > 0) {
                _ptsGroupList.removeLast();
              }
            });
          }),
    );
  }
}

class ColorChoser extends StatefulWidget {
  const ColorChoser({
    Key key,
  }) : super(key: key);

  static Color backgroundColor = Colors.white;
  static Color penColor = Colors.blue;
  static bool showColorSelector = true;

  @override
  _ColorChoserState createState() => _ColorChoserState();
}

class _ColorChoserState extends State<ColorChoser> {
  @override
  Widget build(BuildContext context) {
    return Visibility(
      visible: ColorChoser.showColorSelector,
      child: Positioned(
        bottom: 0,
        left: 0,
        width: MediaQuery.of(context).size.width,
        child: Container(
          height: 60,
          child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: colorList.length,
              itemBuilder: (context, index) {
                return InkWell(
                  onTap: () {
                    setState(() {
                      ColorChoser.penColor = colorList[index];
                    });
                  },
                  child: Padding(
                    padding: const EdgeInsets.symmetric(
                        horizontal: 4.0, vertical: 5.0),
                    child: Container(
                      color: colorList[index],
                      // height: 30,
                      width: 45,
                    ),
                  ),
                );
              }),
        ),
      ),
    );
  }
}

class SignaturePainter extends CustomPainter {
  List<Offset> points;
  List<PointsGroup> grpPointsList = <PointsGroup>[];
  var paintObj;

  SignaturePainter({
    this.grpPointsList = const [],
  });

  @override
  void paint(Canvas canvas, Size size) {
    for (PointsGroup pts in grpPointsList) {
      points = pts.setPoints;
      paintObj = Paint()
        ..color = pts.setColor
        ..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], paintObj);
        }
      }
    }
  }

  @override
  bool shouldRepaint(SignaturePainter oldDelegate) =>
      oldDelegate.points != points;
}

class PointsGroup {
  List<Offset> setPoints = <Offset>[];
  Color setColor;
  PointsGroup({this.setPoints, this.setColor});
}

第一次抽奖时也没有显示该图。笔一抬起,它就开始显示。

PS如果有任何替代方法可以实现所需的多色绘图,那就没问题了。

4

1 回答 1

0

每当触发 onPanStart 时(当用户将手指放在屏幕上时),您都会清除所有点。如果您从中删除_points.clear()onPanStart: (details) {}您将保留用户绘制的所有点。

绘制许多点后,应用程序开始滞后并且帧速率受到影响。当用户在画布上绘制了相当数量的内容时,您会注意到这一点。为了防止出现滞后,一种策略是减少绘制的点数。您可以将点数减半,但仍然可以通过这样做让用户自主绘制他们想要的东西:

final int THRESHOLD = 2;
if (totalPoints % THRESHOLD == 0){
 _points = new List.from(_points)..add(_localPosition);
}

totalPoints是一个你加一的计数器onPanUpdate: (details) {}

另一种技术是使用 RepaintBoundary 小部件https://api.flutter.dev/flutter/widgets/RepaintBoundary-class.html包装扩展 CustomPainter 的子类小部件,在本例中为 CustomPaint 。此小部件将确保仅在需要时重绘画布上发生绘画的区域。通过将刷新渲染限制为一个小部件,您将加快流程并提供更好的结果。

RepaintBoundary(
  child: CustomPaint(
    isComplex: true,
    willChange: false,
    painter: Painter(
      points: _points,
    ),
  ),
),
于 2021-05-11T04:54:40.207 回答