Эффективный рендеринг холста во Flutter
Я пытался разработать приложение для рисования, и все примеры кода, включая код из The Boring Flutter Development Show, не очень хорошо подходят для реального использования.
Основная проблема в том, что CustomPaint
Операция рисования слишком дорогая и перерисовывает каждую точку, каждый кадр. И по мере того, как точки увеличиваются, время рендеринга приложения flutter на кадр значительно увеличивается.
За время, которое я потратил на поиск решения этой проблемы, я нашел эти
RepaintBoundary
: Растрирует слоиПользовательский виджет с использованием
SingleChildRenderObjectWidget
а такжеRenderProxyBox
: должен реализовывать метод рисования и не передавать контроллер
Я не думаю, что какое-либо из вышеперечисленных решений подходит для моих нужд: плавные операции рисования холста без повторного рисования. Я даже пытался упростить пункты, но это не сработало из-за встроенного механизмаCustomPaint
Если бы существовал способ передать холст в качестве виджета и подключить контроллер, было бы легко сохранить захваченные точки и использовать базовые операции с холстом, такие как canvas.drawPath()
или canvas.drawLine()
очень эффективно
Любое предложение было бы полезным. Спасибо!
0 ответов
Это класс контроллера
class DrawingController extends ChangeNotifier {
List<Offset> _points = []
.... // Perform operations on data points
....
void add(Offset point) {
_points.add(point);
notifyListeners();
}
}
Это
CustomPaint
класс
class Painter extends CustomPainter {
DrawingController controller;
Painter(this.controller) : super(repaint: controller); //This is important
@override
void paint(Canvas canvas, Size size) {
//Paint function
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
А в Детекторе жестов просто позвоните
controller.add(point)
добавлять новые точки по мере их захвата
Я не уверен, что это наиболее эффективный способ рисования, но он сократил время рисования до 13 мс на экране с частотой 60 Гц и до 9 мс на экране с частотой 120 Гц. Один заметный недостаток заключается в том, что один штрих (от onTapdownEvent до onDragEndEvent) отображается довольно медленно (до 18 мс), когда штрих имеет много точек. Эта проблема исчезает, как только вы начинаете новый ход. Я пробовал спрашивать на нескольких форумах, и это лучшее, что я смог придумать, покопавшись в исходном коде флаттера.
Я профилировал эту функциональность на устройстве Snapdragon 855, поэтому процессор не является узким местом. Если кто-нибудь найдет лучшее решение, опубликуйте его.
Полезный совет - добавить Timer.run(setState()). Таким образом, он обновляется только тогда, когда это возможно. Вместо загрузки update1 update2 update3... и т. Д. Он загружает update1, затем, если он может, загружает update2, но если update1 занимает слишком много времени, он переходит к update3. В целом это выглядит более плавно, но не обязательно ускоряет его. Образец:
scaleStart(ScaleStartDetails d) => startPoint = d.focalPoint - _offset;
scaleUpdate(ScaleUpdateDetails d) {
_offset = d.focalPoint - startPoint;
scale = min(max(1, scale * (d.scale + 13) / 14), 128);
Timer.run(() => setState(() {}));
}