【问题标题】:Flutter Custom Painter drawing is laggyFlutter Custom Painter 绘图滞后
【发布时间】:2020-11-15 15:55:06
【问题描述】:

我正在尝试编写一个绘图应用程序,用户可以在其中选择不同的笔颜色并绘制彩色绘图。我创建了一个 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});
}

此外,第一次抽奖时未显示该图纸。只要笔 抬起它开始显示。

P.S.如果有任何替代方法可以实现所需的多色绘图,那就可以了。

【问题讨论】:

  • 这是您的调试应用测试视频吗?
  • @D.R.是的,它在 android 模拟器上的调试应用程序
  • 试试profile模式,也许你会得到更好的性能,甚至最好的release模式......
  • @D.R.知道为什么第一次没有显示绘图,移除笔后它开始显示。
  • 我的一个应用程序有相同的前任,但它工作得很好......我用它来绘制签名......但我不知道你的代码出了什么问题...... .

标签: flutter canvas drawing custom-painting


【解决方案1】:

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

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

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,
    ),
  ),
),

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-17
    • 2023-01-12
    • 2020-04-09
    • 2019-03-25
    • 1970-01-01
    • 2017-09-29
    相关资源
    最近更新 更多