Понимание Flutter Render Engine - PullRequest
0 голосов
/ 25 ноября 2018

Документы здесь о том, как обновить ListView, скажем:

В Flutter, если вам нужно обновить список виджетов внутри setState (), выбыстро увидит, что ваши данные не изменились визуально.Это происходит потому, что когда вызывается setState (), механизм рендеринга Flutter просматривает дерево виджетов, чтобы увидеть, изменилось ли что-нибудь.Когда он попадает в ваш ListView, он выполняет проверку == и определяет, что два ListView одинаковы.Ничего не изменилось, поэтому обновление не требуется.

Чтобы упростить обновление ListView, создайте новый List внутри setState () и скопируйте данные из старого списка в новый список.

Я не понимаю, как механизм рендеринга определяет, есть ли какие-либо изменения в дереве виджетов в этом случае.

AFAICS, мы заботимся о вызове setState, который отмечает State объект как грязный и просит его восстановить.Как только он восстановится, появится новый ListView, не так ли?Так почему же проверка == говорит, что это тот же объект?

Кроме того, новый List будет внутренним для объекта State, сравнивает ли движок Flutter все объекты внутри объекта State?Я думал, что это только сравнил дерево Widget.

Итак, в основном я не понимаю, как Render Engine решает, что он собирается обновлять, а что игнорирует, поскольку я не вижу, как создание нового List отправляет какую-либо информацию в Render Engine.Как говорят в документации, Render Engine просто ищет новый ListView ... И AFAIK новый List не создаст новый ListView.

1 Ответ

0 голосов
/ 25 ноября 2018

Флаттер не состоит только из виджетов .

Когда вы звоните setState, вы помечаете виджет как грязный.Но этот виджет на самом деле не то, что вы отображаете на экране.Существуют виджеты для создания / изменения RenderObjects ;это те объекты RenderObject, которые рисуют ваш контент на экране.

Связь между RenderObjects и виджетами осуществляется с помощью нового вида виджетов: RenderObjectWidget (например, LeafRenderObjectWidget )

Большинство виджетов, предоставленных Flutterв некоторой степени являются RenderObjectWidget, включая ListView.

Типичным примером RenderObjectWidget может быть такой:

class MyWidget extends LeafRenderObjectWidget {
  final String title;

  MyWidget(this.title);

  @override
  MyRenderObject createRenderObject(BuildContext context) {
    return new MyRenderObject()
      ..title = title;
  }

  @override
    void updateRenderObject(BuildContext context, MyRenderObject renderObject) {
      renderObject
        ..title = title;
    }
}

В этом примере используется виджет для создания / обновления RenderObject.Недостаточно сообщить платформе, что есть что перекрасить.

Чтобы перерисовать RenderObject, нужно вызвать markNeedsPaint или markNeedsLayout для нужного объекта renderObject.

Обычно это делается самим RenderObject с использованием пользовательского установщика полей следующим образом:

class MyRenderObject extends RenderBox {
  String _title;
  String get title => _title;
  set title(String value) {
    if (value != _title) {
      markNeedsLayout();
      _title = value;
    }
  }
}

Обратите внимание на if (value != previous).

Эта проверка гарантирует, что при перестройке виджетаничего не меняя, Flutter не ретранслирует и не перерисовывает ничего.

Именно из-за этого точного условия мутирование List или Map не приводит к повторному отображению ListView.Он в основном имеет следующее:

List<Widget> _children;
List<Widget> get children => _children;
set children(List<Widget> value) {
  if (value != _children) {
    markNeedsLayout();
    _children = value;
  }
}

Но это означает, что если вы измените список вместо создания нового, RenderObject не будет помечен как нуждающийся в пересылке / перерисовке.Поэтому никаких визуальных обновлений не будет.

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