flutter: пользовательский художник не перерисовывает, хотя shouldRepaint () возвращает true - PullRequest
0 голосов
/ 11 июля 2020

Я тестирую FFI с флаттером, получая данные о цвете со стороны C / C ++ и раскрашивая экран, используя CustomPainter.

Но, к моему удивлению, хотя я установил рисовальщик всегда перерисовывать, * Функция 1004 * вызывается только дважды.

Код

class _ColorViewPainter extends CustomPainter {
  Color clrBackground;

  _ColorViewPainter({
    this.clrBackground = Colors.black
  });

  @override
  bool shouldRepaint(_ColorViewPainter old) => true;

  @override
  void paint(Canvas canvas, Size size) {
    print("paint: start");

    final color = ffiGetColor().ref;

    final r = color.r;
    final g = color.g;
    final b = color.b;

    print("color: $r, $g, $b");

    final paint = Paint()
        ..strokeJoin = StrokeJoin.round
        ..strokeWidth = 1.0
        ..color = Color.fromARGB(255, r, g, b)
        ..style = PaintingStyle.fill;

    final width = size.width;
    final height = size.height;
    final content = Offset(0.0, 0.0) & Size(width, height);
    canvas.drawRect(content, paint);

    print("paint: end");
  }
}

Функция ffiGetColor() просто извлекает структуру цветного RGB со стороны C / C ++. Я вижу, что экран обновляется дважды, и в журнале написано:

I/flutter (12096): paint: start
I/flutter (12096): color: 255, 0, 0
I/flutter (12096): paint: end
I/flutter (12096): paint: start
I/flutter (12096): color: 0, 255, 0
I/flutter (12096): paint: end
I/Surface (12096): opservice is null false

Но это все. Хотя я явно хочу его перекрасить в shouldRepaint. flutter не смог этого сделать.

Что случилось?

вот моя среда

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel dev, v1.18.0-dev.5.0, on Mac OS X 10.15.5 19F101, locale en-CA)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
[✓] Android Studio (version 4.0)
[✗] Cannot determine if IntelliJ is installed
    ✗ Directory listing failed
[✓] VS Code (version 1.44.2)
[✓] Connected device (1 available)

! Doctor found issues in 1 category.

1 Ответ

1 голос
/ 12 июля 2020

Благодаря советам @pskink мне удалось заставить мой CustomPainter непрерывно перерисовываться, хотя он все еще не идеален.

См. dart / flutter: CustomPaint обновляется с меньшей скоростью, чем обновление значения ValueNotifier

Поскольку в текущем решении все еще существует проблема с частотой обновления, я просто кратко сообщаю о том, что у меня есть:

Мне в основном нужно создать уведомитель и назначить ffi -получено значение для него в нужном месте с помощью опроса.


// in initState() of State class
_notifier = ValueNotifier<NativeColor>(ffiGetColor().ref);

...

// in a timer method
_notifier.value = ffiGetColor().ref;

Затем с помощью CustomPaint привяжите уведомитель к перерисовке в его конструкторе

  @override
  Widget build(BuildContext context) {
    return Container(

      ...


        child: CustomPaint(
          painter: _ColorViewPainter(
              context: context,
              notifier: _notifier,
              ...
          )
        )
    );
  }

class _ColorViewPainter extends CustomPainter {
  ValueNotifier<NativeColor> notifier;
  BuildContext context;
  Color clrBackground;

  _ColorViewPainter({this.context, this.notifier, this.clrBackground})
    : super(repaint: notifier) {
  }

  @override
  bool shouldRepaint(_ColorViewPainter old) {
    print('should repaint');
    return true;
  }

  @override
  void paint(Canvas canvas, Size size) {
    print("paint: start");
    final r = notifier.value.r;
    final g = notifier.value.g;
    final b = notifier.value.b;
    print("color: $r, $g, $b");
    final paint = Paint()
        ..strokeJoin = StrokeJoin.round
        ..strokeWidth = 1.0
        ..color = Color.fromARGB(255, r, g, b)
        ..style = PaintingStyle.fill;

    final width = size.width;
    final height = size.height;
    final content = Offset(0.0, 0.0) & Size(width, height);
    canvas.drawRect(content, paint);
    print("paint: end");
  }

}

GOTCHAS

ValueNotifier полагается на следующее, чтобы иметь возможность запускать уведомление для своих слушателей

  • Тип значения, к которому он привязан, определил operator ==
  • ValueNotifier поле значения, к которому привязывается интересующий объект данных, явно переназначается с НОВЫМ объектом данных при изменениях.

Это очень важно, когда мы привязываем уведомитель к пользовательский класс, Wi th, который мы должны

  • Перегрузить его operator ==.
  • Назначить новый объект ValueNotifier<MyClass>.value вместо вызова обычных методов текущего объекта для изменения значения.

В противном случае CustomPaint paint() не будет вызываться при желаемых изменениях.

В качестве другого примера, этот настраиваемый класс не подходит для связывания с ValueNotifier, потому что там не перегружен operator==:

class MyClass {
  int prop = 0;

  void changeValue(newValue) {
    prop = newValue;
  }

}

В качестве другого примера предположим, что у нас есть собственный класс:

class MyClass {
  int prop = 0;

  @override
  bool operator ==(covariant MyClass other) {
    return other is MyClass && prop != other. prop;
  }

  void changeValue(newValue) {
    prop = newValue;
  }

}

Это будет работать:


class _MyViewState extends State<MyView> {
  ValueNotifier<MyClass> notifier;
  Timer _timer;

  ....

  @override
  initState() {
    super.initState();

    notifier = ValueNotifier<MyClass>(MyClass());
    _timer = Timer.periodic(Duration(milliseconds: 10), _updateData);
  }

  _updateData(Timer t) {
     var myObj = MyClass(newValue);
     notifier.value = myObj;
  }

}

Но это не сработает.

class _MyViewState extends State<MyView> {
  ValueNotifier<MyClass> notifier;
  Timer _timer;

  ....

  @override
  initState() {
    super.initState();

    notifier = ValueNotifier<MyClass>(MyClass());
    _timer = Timer.periodic(Duration(milliseconds: 10), _updateData);
  }


  _updateData(Timer t) {
     var newValue = getNewValueSomewhere();
     notifier.value.changeValue(newValue);
  }


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...