1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-21.md 39 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Как двадцать первая статья в серии, эта статья рассматривает общие принципы рендера Flutter Framework с другого ракурса, углубленно анализируя процесс отрисовки после создания слоев (Layers) в Flutter, чтобы разработчики лучше понимали принципы рендера и логику реализации.

Ссылки на статьи:

Полный практический гайд по Flutter

Серия статей "Мир Flutter"

1. Обзор Layers

Напомним, что в Flutter компоненты проходят через изменения от Widget до Element, затем до RenderObject и наконец до Layer. Определение того, какие объекты составят слой (Layer), зависит от значения свойства isRepaintBoundary в каждом RenderObject.

При вызове метода setState, RenderObject начинает поиск вверх по родительской цепочке, где значение isRepaintBoundary равно true. Это определяет область, которая будет перерисована. Другими словами, это способ определить, какие области будут обновлены.

К примеру, при переходе между маршрутами с помощью Navigator, каждый маршрут имеет внутри себя компонент RepaintBoundary, который имеет значение isRepaintBoundary равное true. Таким образом, маршруты становятся независимыми слоями.

Поэтому связанные RenderObject вместе образуют слой (Layer), а дерево слоев (Layer Tree) в конечном итоге передается в движок Flutter для отображения.

Тогда как работает слой? Какова его сущность? Какие шаги предпринимает Flutter Framework для отправки слоев в движок?## 2. Отрисовка в Flutter Framework

Ответив на вопросы выше относительно слоев, давайте сделаем предположение: если мы игнорируем готовые компоненты Flutter Framework, как нам создать картинку? Или говоря другими словами, как создать слой?

Допустим, следующий код показывает, как можно отобразить центрально расположенный синий квадрат размером 100x100 пикселей, используя такие менее знакомые объекты, как PictureRecorder, Canvas и SceneBuilder, вместо использования Widgets, RenderObjects или Layers.

import 'dart:ui' as ui;

void main() {
  ui.window.onBeginFrame = beginFrame;

  ui.window.scheduleFrame();
}

void beginFrame(Duration frameTime) {
  final double devicePixelRatio = ui.window.devicePixelRatio;

  // Создаем холст для рисования
  final ui.PictureRecorder recorder = ui.PictureRecorder();

  // На основе холста создаем объект Canvas
  final ui.Canvas canvas = ui.Canvas(recorder);
  canvas.scale(devicePixelRatio, devicePixelRatio);

  var centerX = ui.window.physicalSize.width / 2.0;
  var centerY = ui.window.physicalSize.height / 2.0;

  // Рисуем синий прямоугольник размером 100x100 пикселей
  canvas.drawRect(
      Rect.fromCenter(
          center: Offset.zero,
          width: 100,
          height: 100),
      new Paint()..color = Colors.blue);

  // Закончим рисование
  final ui.Picture picture = recorder.endRecording();

  final ui.SceneBuilder sceneBuilder = ui.SceneBuilder()
    ..pushOffset(centerX, centerY)
    ..addImage(ui.Offset.zero, picture)
    ..pop();
}
```  ui.окно.рендер(sceneBuilder.построить());
}

Поскольку в Flutter создание объекта Canvas обязательно требует PictureRecorder, а PictureRecorder как следует из названия, используется для создания изображения для записи рисунка, то в приведённом выше коде:

  • Сначала создаётся PictureRecorder;
  • Затем используя PictureRecorder создаётся Canvas;
  • Далее с помощью Canvas рисуется синий квадрат;
  • После завершения рисования через PictureRecorder.endRecording() получается Picture;
  • Через SceneBuilder.pushOffset и SceneBuilder.addPicture добавляется отрисованное содержимое;
  • В конце через ui.window.render происходит отрисовка.

Внимание: метод render ограничен вызовом только внутри onBeginFrame или onDrawFrame. Поэтому в коде есть строка window.onBeginFrame = beginFrame;.

Flutter Framework в своей нижней части использует window.render для окончательной отрисовки. Как показывает следующий код, метод render принимает параметром объект Scene, и сам метод является native, что указывает на то, что Flutter Framework передаёт Engine объект Scene.

void render(Scene сцена) native 'Window_render';

А что такое Scene? Где же Layer? И какие между ними отношения?

Три. Отношения между Scene и Layer

---В Flutter объект Scene фактически является нативным объектом, который соответствует структуре scene.cc в модуле Engine. Внутри scene.cc содержится поле layer_tree_, которое используется для отрисовки, поэтому можно сделать вывод, что объект Scene связан с layer_tree_ внутри Engine.Далее следует отметить, что в фреймворке Flutter объект Scene может быть создан только через SceneBuilder, а в SceneBuilder присутствуют различные методы, такие как pushOffset, pushClipRect, pushOpacity и так далее. Выполнение этих методов позволяет создать соответствующий объект EngineLayer.

  OffsetEngineLayer pushOffset(double dx, double dy, { OffsetEngineLayer oldLayer }) {
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOffset'));
    final OffsetEngineLayer layer = OffsetEngineLayer._(_pushOffset(dx, dy));
    assert(_debugPushLayer(layer));
    return layer;
  }
  EngineLayer _pushOffset(double dx, double dy) native 'SceneBuilder_pushOffset';

Итак, до создания объекта Scene с помощью SceneBuilder, можно использовать методы типа push для создания объектов EngineLayer, например, в примере с синим квадратом, SceneBuilder использует метод pushOffset для создания соответствующего слоя смещения.

Затем рассмотрим объект Layer в фреймворке Flutter, где видно, что по умолчанию в объекте Layer уже есть поле EngineLayer, что указывает на связь между Layer и SceneBuilder.

  @protected
  ui.EngineLayer get engineLayer => _engineLayer;

  @protected
  set engineLayer(ui.EngineLayer value) {
    _engineLayer = value;
    if (!alwaysNeedsAddToScene) {
      
      if (parent != null && !parent.alwaysNeedsAddToScene) {
        parent.markNeedsAddToScene();
      }
    }
  }
  ui.EngineLayer _engineLayer;
  
  /// Переопределите этот метод для загрузки этого слоя в движок.
  ///
  /// Верните слой движка для сохраненного рендера. Когда нет соответствующего слоя движка, вернётся null.
```Кроме того, в объекте `Layer` имеется ключевой метод `addToScene`, который реализуется в производных классах и после выполнения которого получается объект `EngineLayer`. Этот метод требует передачи объекта `SceneBuilder`, и его реализация включает в себя классы `OffsetLayer` и `PictureLayer` и другие. Изображение:

Поэтому, как показано ниже в коде, можно заметить реализацию методов `addToScene` для классов `OffsetLayer` и `PictureLayer`:

- `PictureLayer` вызывает метод `addPicture` класса `SceneBuilder`;
- `OffsetLayer` вызывает метод `pushOffset` класса `SceneBuilder`;

```dart
class PictureLayer extends Layer {
  ...
  @override
  void addToScene(ui.SceneBuilder builder, [Offset layerOffset = Offset.zero]) {
    builder.addPicture(layerOffset, picture, isComplexHint: isComplexHint, willChangeHint: willChangeHint);
  }
  ...
}

class OffsetLayer extends ContainerLayer {
  ...
  OffsetLayer({Offset offset = Offset.zero}) : _offset = offset;

  @override
  void addToScene(ui.SceneBuilder builder, [Offset layerOffset = Offset.zero]) {
    engineLayer = builder.pushOffset(
        layerOffset.dx + offset.dx,
        layerOffset.dy + offset.dy,
        oldLayer: _engineLayer as ui.OffsetEngineLayer,
    );
    addChildrenToScene(builder);
    builder.pop();
  }
  ...
}

На этом этапе SceneBuilder и Layer успешно связаны через методы EngineLayer и addToScene, а также Scene, который передается методом window.render, был создан с помощью SceneBuilder. Поэтому, как показано на следующем изображении, Layer и Scene таким образом "соединен" вместе.

Изображение:Перед этим синим прямоугольником кода, как показано ниже, здесь используется подход с использованием Layer, что ближе к реализации Flutter Framework: через rootLayer создаются последовательно Layer деревья с помощью метода append, а затем rootLayer вызывает метод addToScene, который выполняет метод addChildrenToScene, тем самым запуская выполнение метода addToScene для всех потомков Layer.```dart import 'dart:ui' as ui;

void main() { ui.window.onBeginFrame = beginFrame;

ui.window.scheduleFrame(); }

void beginFrame(Duration timeStamp) { final double devicePixelRatio = ui.window.devicePixelRatio;

// Создание холста final ui.PictureRecorder recorder = ui.PictureRecorder();

// Создание Canvas на основе холста final ui.Canvas canvas = ui.Canvas(recorder); canvas.scale(devicePixelRatio, devicePixelRatio);

var centerX = ui.window.physicalSize.width / 2.0; var centerY = ui.window.physicalSize.height / 2.0; }```### 4. Виды слоев

Здесь мы рассмотрим наиболее распространенные виды слоев в Flutter. Как показано на следующей схеме, слои обычно можно разделить на ContainerLayer и непосредственно на слои.

Слои

ContainerLayer могут иметь дочерние узлы и имеют метод append. Они могут быть разделены на несколько категорий:

  • Смещение (OffsetLayer / TransformLayer);
  • Прозрачность (OpacityLayer);
  • Обрезка (ClipRectLayer / ClipRRectLayer / ClipPathLayer);
  • Тень (PhysicalModelLayer).

Почему эти слои являются ContainerLayer? Это потому что они представляют собой операции по составлению пикселей и сами по себе не способны "рисовать" компоненты. Например, как в случае с маленьким синим квадратом, если требуется отобразить изображение, это обычно требует сочетания с PictureLayer.

Например, при создании ClipRRect, его внутренний RenderClipRRect может создать ClipRRectLayer при вызове pushClipRRect, а новый ClipRRectLayer будет добавлен в качестве потомка родительского слоя через метод append.

Некоторые слои не являются ContainerLayer и не имеют дочерних узлов, такие как: ```- PictureLayer используется для рисования изображений; большинство компонентов Flutter рисуются именно здесь;

  • TextureLayer используется для внешних текстур, таких как воспроизведение видео или данные камеры;
  • PlatformViewLayer используется для встраивания текстур PlatformView на iOS;

Пример того, как компоненты рисуются на Canvas, который берется из PaintingContext. Как показано ниже, после выполнения рисования через _repaintCompositedChild, полученный Picture передается в PictureLayer.picture.

void stopRecordingIfNeeded() {
    if (!_isRecording) return;
    _currentLayer.picture = _recorder.endRecording();
    _currentLayer = null;
    _recorder = null;
    _canvas = null;
}

5. Внешний и внутренний аспекты слоя (Layer)

После того как мы узнали, как Layer отправляет данные для отрисовки, теперь рассмотрим процесс обновления и повторного использования слоев.

Как известно, когда свойство isRepaintBoundary объекта RenderObject равно true, фреймворк Flutter автоматически создает слой OffsetLayer, который "обволакивает" эту область. Обновление содержимого внутри слоя обычно не влияет на другие слои.

Как происходит обновление слоев? Это связано с методами markNeedsAddToScene и updateSubtreeNeedsAddToScene в составе слоя.

Вот пример кода:

@protected
@visibleForTesting
void markNeedsAddToScene() {
    // Уже помечен. Кратчайший путь.
    if (_needsAddToScene) {
        return;
    }
```    _needsAddToScene = true;
  }
  
  @override
  void updateSubtreeNeedsAddToScene() {
    super.updateSubtreeNeedsAddToScene();
    Layer child = firstChild;
    while (child != null) {
      child.updateSubtreeNeedsAddToScene();
      _needsAddToScene = _needsAddToScene || child._needsAddToScene;
      child = child.nextSibling;
    }
  }
```Метод `markNeedsAddToScene` просто устанавливает значение `_needsAddToScene` равным `true`. Метод `updateSubtreeNeedsAddToScene` проходит по всем потомкам (`children`) и использует рекурсивный вызов `updateSubtreeNeedsAddToScene()` для проверки необходимости обновления каждого потомка. Если хотя бы один потомок требует обновления, то текущий слой также будет помечен как требующий обновления.

Аналогично тому, как `setState` помечает компонент как `_dirty`, **когда `_needsAddToScene` равно `true`, метод `addToScene` данного слоя будет вызван; если же `_needsAddToScene` равно `false` и `_engineLayer` не является пустым значением, это указывает на возможность повторного использования слоя**.

```dart
void _addToSceneWithRetainedRendering(ui.SceneBuilder builder) {

    if (!_needsAddToScene && _engineLayer != null) {
        builder.addRetained(_engineLayer);
        return;
    }
    addToScene(builder);

    _needsAddToScene = false;
}

Да, когда значение _needsAddToScene равно false, это говорит о том, что данный слой не требует обновления. Если при этом существует _engineLayer, этот слой может быть повторно использован для отрисовки. Например, при открытии нового экрана нижний экран остается без изменений и используется для составления общего изображения, поэтому его слои могут быть повторно использованы для отрисовки.

Когда вызывается markNeedsAddToScene?Как показано на следующей схеме, когда параметры потомков Layer, такие как picture в PictureLayer или offset в OffsetLayer, изменяются, Layer активно вызывает метод markNeedsAddToScene, чтобы пометить себя как "грязный" слой. Кроме того, если свойство engineLayer в Layer меняется, это пытается спровоцировать родительский Layer вызвать markNeedsAddToScene, что приведёт к изменениям в родительском слое.```dart @protected set engineLayer(ui.EngineLayer value) { _engineLayer = value; if (!alwaysNeedsAddToScene) { if (parent != null && !parent.alwaysNeedsAddToScene) { parent.markNeedsAddToScene(); } } }


Метод `updateSubtreeNeedsAddToScene` вызывается во время выполнения `buildScene`. Перед вызовом `addToScene` выполняется ещё один вызов `updateSubtreeNeedsAddToScene`, который проверяет все дочерние узлы и определяет, требуется ли их изменение.

```dart
ui.Scene buildScene(ui.SceneBuilder builder) {
  List<PictureLayer> temporaryLayers;
  assert(() {
    if (debugCheckElevationsEnabled) {
      temporaryLayers = _debugCheckElevations();
    }
    return true;
  }());
  updateSubtreeNeedsAddToScene();
  addToScene(builder);

  _needsAddToScene = false;
  final ui.Scene scene = builder.build();

  return scene;
}

Шестая глава: Структура слоёв в Flutter Framework

Наконец, вернёмся к Flutter Framework. В Flutter Framework метод _window.render вызывается внутри метода compositeFrame класса RenderView; сам же RenderView инициализируется в методе initRenderView класса RendererBinding; а этот метод вызывается при выполнении initInstances, то есть при запуске runApp.Проще говоря, можно сказать, что при запуске runApp создаётся RenderView, а его внутренний метод compositeFrame использует _window.render для отправки команд на отрисовку слоёв.

void составнойРамки() {
    Timeline.startSync('Составление', arguments: timelineWhitelistArguments);
    try {
        final ui.SceneBuilder builder = ui.SceneBuilder();
        final ui.Scene сцена = слой.построитьСцену(билдер);
        if (автоматическаяНастройкаSystemUi)
            _обновитьSystemChrome();
        _окно.рендер(сцена);
        сцена.disposing();
        assert(() {
            if (debugRepaintRainbowEnabled || debugRepaintTextRainbowEnabled)
                debugCurrentRepaintColor = debugCurrentRepaintColor.cWithHue((debugCurrentRepaintColor.hue + 2.0) % 360.0);
            return true;
        }());
    } finally {
        Timeline.finishSync();
    }
}

Поэтому когда вызывается runApp, Flutter создаёт RenderView, а в методе drawFrame окна вызывается renderView.compositeFrame() для подтверждения отрисовки. RenderView как корневой узел имеет rootLayer, который является подклассом OffsetLayerTransformLayer. Это корневой узел слоев в Flutter.image

Для примера рассмотрим следующий простой некорректный код, который после запуска выводит черный пустой экран. В этом случае мы можем использовать метод debugDumpLayerTree для печати структуры слоев.

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // Этот виджет является корнем вашего приложения.
  @override
  Widget build(BuildContext context) {
    new Future.delayed(Duration(seconds: 1), () {
      debugDumpLayerTree();
    });
    return MaterialApp(
      title: 'GSY Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Container(),
      // routes: routers,
    );
  }
}

Результат печати представлен ниже:

По умолчанию из-за механизма создания слоев (isRepaintBoundary равен true) автоматически создается один OffsetLayer, а также требуется хотя бы один OffsetLayer и PictureLayer для работы с Canvas.

Layer tree dump:
OffsetLayer@900.0% size
  | PictureLayer@900.0% size

Этот вывод показывает структуру слоев, которая была создана автоматически.Также стоит отметить, что TransformLayer как rootLayer имеет владельцем RenderView, и у него есть два дочерних узла: child1OffsetLayer и child2PictureLayer.

I/flutter (32494): TransformLayer#f8fa5
I/flutter (32494):  │ владелец: RenderView#2d51e
I/flutter (32494):  │ создатель: [root]
I/flutter (32494):  │ смещение: Offset(0.0, 0.0)
I/flutter (32494):  │ преобразование:
I/flutter (32494):  │   [0] 2.8,0.0,0.0,0.0
I/flutter (32494):  │   [1] 0.0,2.8,0.0,0.0
I/flutter (32494):  │   [2] 0.0,0.0,1.0,0.0
I/flutter (32494):  │   [3] 0.0,0.0,0.0,1.0
I/flutter (32494):  │
I/flutter (32494):  ├─потомок 1: OffsetLayer#4503b
I/flutter (32494):  │ │ создатель: RepaintBoundary ← _FocusMarker ← Semantics ← FocusScope
I/flutter (32494):  │ │   ← PageStorage ← Offstage ← _ModalScopeStatus ←
I/flutter (32494):  │ │   _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#e1be1]
I/flutter (32494):  │ │   ← _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#95107] ←
I/flutter (32494):  │ │   Stack ← _Theatre ←
I/flutter (32494):  │ │   Overlay-[LabeledGlobalKey<OverlayState>#ceb36] ← ⋯
I/flutter (32494):  │ │ смещение: Offset(0.0, 0.0)
I/flutter (32494):  │ │
I/flutter (32494):  │ └─потомок 1: OffsetLayer#e8309
I/flutter (32494):  │     создатель: RepaintBoundary-[GlobalKey#bbad8] ← IgnorePointer ←
I/flutter (32494):  │       FadeTransition ← FractionalTranslation ← SlideTransition ←
I/flutter (32494):  │       _FadeUpwardsPageTransition ← AnimatedBuilder ← RepaintBoundary
I/flutter (32494):  │       ← _FocusMarker ← Semantics ← FocusScope ← PageStorage ← ⋯
I/flutter (32494):  │     смещение: Offset(0.0, 0.0)
I/flutter (32494):  │
I/flutter (32494):  └─потомок 2: PictureLayer#be4f1
I/flutter (32494):      границы отрисовки: Rect.fromLTRB(0.0, 0.0, 1080.0, 2030.0)

Согласно вышеуказанному логу можно сделать вывод:- OffsetLayer создается с помощью RepaintBoundary, а его источник — это Overlay. В Flutter Overlay используется для создания глобальных плавающих компонентов, и он создаётся в Navigator приложения MaterialApp как независимый слой;

  • Дочерним элементом OffsetLayer является PageStorage, который создаётся путём маршрутизации (Route) и представляет собой первый по умолчанию маршрут.

Таким образом, теперь понятно, почему Overlay может быть глобально плавающим во всех маршрутах приложения MaterialApp.

Вот пример кода, где к исходному коду добавлен Scaffold, после чего выполнена функция debugDumpLayerTree.

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    new Future.delayed(Duration(seconds: 1), () {
      debugDumpLayerTree();
    });
    return MaterialApp(
      title: 'GSY Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Container(),
      ),
      // routes: routers,
    );
  }
}
```Здесь можно заметить появление двух новых слоев: `PhysicalModelLayer` и `PictureLayer`. `PhysicalModelLayer` используется для установки эффектов тени и других свойств, таких как отключение тени у `AppBar` при выключении `debugDisablePhysicalShapeLayers`. А `PictureLayer` служит для рисования.

```markdown
I/flutter (32494): TransformLayer#ac14b
I/flutter (32494):  владелец: RenderView#f5ecc
I/flutter (32494):  создатель: [root]
I/flutter (32494):  смещение: Offset(0.0, 0.0)
I/flutter (32494):  преобразование:
I/flutter (32494):    [0] 2.8, 0.0, 0.0, 0.0
I/flutter (32494):    [1] 0.0, 2.8, 0.0, 0.0
I/flutter (32494):    [2] 0.0, 0.0, 1.0, 0.0
I/flutter (32494):    [3] 0.0, 0.0, 0.0, 1.0
I/flutter (32494): 
I/flutter (32494): ├─потомок 1: OffsetLayer#c0128
I/flutter (32494):   создатель: RepaintBoundary  _FocusMarker  Semantics  FocusScope
I/flutter (32494):      PageStorage  Offstage  _ModalScopeStatus 
I/flutter (32494):     _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#fe143]
I/flutter (32494):      _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#9cb60] 
I/flutter (32494):     Stack  _Theatre 
I/flutter (32494):     Overlay-[LabeledGlobalKey<OverlayState>#ee455]  
I/flutter (32494):   смещение: Offset(0.0, 0.0)
I/flutter (32494):  
I/flutter (32494):  └─потомок 1: OffsetLayer#fb2a6
I/flutter (32494):     создатель: RepaintBoundary-[GlobalKey#fd46b]  IgnorePointer 
I/flutter (32494):       FadeTransition  FractionalTranslation  SlideTransition 
I/flutter (32494):       _FadeUpwardsPageTransition  AnimatedBuilder  RepaintBoundary
I/flutter (32494):        _FocusMarker  Semantics  FocusScope  PageStorage  
I/flutter (32494):     смещение: Offset(0.0, 0.0)
I/flutter (32494):    
I/flutter (32494):    └─потомок 1: PhysicalModelLayer#f1460
I/flutter (32494):       создатель: PhysicalModel  AnimatedPhysicalModel  Material 
```I/flutter (32494):          PrimaryScrollController  _ScaffoldScope  Scaffold  Semantics
 I/flutter (32494):           Builder  RepaintBoundary-[GlobalKey#fd46b]  IgnorePointer 
 I/flutter (32494):          FadeTransition  FractionalTranslation  
 I/flutter (32494):        выпуклость: 0.0
 I/flutter (32494):        цвет: Color(0xfffafafa)
 I/flutter (32494):       
 I/flutter (32494):       └─потомок 1: PictureLayer#f800f
 I/flutter (32494):           границы рисунка: Rect.fromLTRB(0.0, 0.0, 392.7, 738.2)
 I/flutter (32494):  
 I/flutter (32494):  └─потомок 2: PictureLayer#af14d
 ```I/flutter (32494):      paint bounds: Rect.fromLTRB(0.0, 0.0, 1080.0, 2030.0)  
 I/flutter (32494):```markdown
 Итак, после того как вы снова используете `Navigator`, чтобы перейти на другой экран, и печатаете дерево слоёв (`Layer` tree) на новой странице, можно заметить появление новых слоёв  `PictureLayer`, `AnnotatedRegionLayer` и `TransformLayer`. В частности, новый слой `AnnotatedRegionLayer` используется для управления отображением области состояния в верхней части нового экрана.
 ``````markdown
 I/flutter (32494): TransformLayer#12e21
 I/flutter (32494):   владелец: RenderView#aa5c7
 I/flutter (32494):   создатель: [root]
 I/flutter (32494):   смещение: Offset(0.0, 0.0)
 I/flutter (32494):   преобразование:
 I/flutter (32494):     [0] 2.8,0.0,0.0,0.0
 I/flutter (32494):     [1] 0.0,2.8,0.0,0.0
 I/flutter (32494):     [2] 0.0,0.0,1.0,0.0
 I/flutter (32494):     [3] 0.0,0.0,0.0,1.0
 I/flutter (32494):  
 I/flutter (32494):  ├─потомок 1: OffsetLayer#fc176
 I/flutter (32494):    создатель: RepaintBoundary  _FocusMarker  Semantics  FocusScope
 I/flutter (32494):       PageStorage  Offstage  _ModalScopeStatus 
 I/flutter (32494):      _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#43140]
 I/flutter (32494):       _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#46f19] I/flutter (32494):      Stack  _Theatre 
I/flutter (32494):      Overlay-[LabeledGlobalKey<OverlayState>#af6f4]  
I/flutter (32494):    смещение: Offset(0.0, 0.0)
I/flutter (32494):   
I/flutter (32494):   └─потомок 1: OffsetLayer#b6e14
I/flutter (32494):      создатель: RepaintBoundary-[GlobalKey#0ce90]  IgnorePointer 
I/flutter (32494):        FadeTransition  FractionalTranslation  SlideTransition 
I/flutter (32494):        _FadeUpwardsPageTransition  AnimatedBuilder  RepaintBoundary
I/flutter (32494):         _FocusMarker  Semantics  FocusScope  PageStorage  
I/flutter (32494):      смещение: Offset(0.0, 0.0)
I/flutter (32494):     
I/flutter (32494):     └─потомок 1: PhysicalModelLayer#4fdc6
I/flutter (32494):        создатель: PhysicalModel  AnimatedPhysicalModel  Material 
I/flutter (32494):          PrimaryScrollController  _ScaffoldScope  Scaffold 
I/flutter (32494):          ClipDemoPage  Semantics  Builder 
I/flutter (32494):          RepaintBoundary-[GlobalKey#0ce90]  IgnorePointer 
I/flutter (32494):          FadeTransition  
I/flutter (32494):        выступание: 0.0
I/flutter (32494):        цвет: Color(0xfffafafa)
I/flutter (32494):       
I/flutter (32494):       ├─потомок 1: PictureLayer#6ee26
I/flutter (32494):          границы рисунка: Rect.fromLTWH(0.0, 0.0, 392.7, 738.2)
I/flutter (32494):       
```I/flutter (32494):       ├─потомок 2: AnnotatedRegionLayer<SystemUiOverlayStyle>#cbeaf
I/flutter (32494):         значение: {systemNavigationBarColor: 4278190080,
I/flutter (32494):           systemNavigationBarDividerColor: null, statusBarColor: null,
I/flutter (32494):           statusBarBrightness: Brightness.dark, statusBarIconBrightness:
I/flutter (32494):           Brightness.light, systemNavigationBarIconBrightness:
I/flutter (32494):           Brightness.light}
I/flutter (32494):         размер: Size(392.7, 83.6)
I/flutter (32494):         смещение: Offset(0.0, 0.0)
I/flutter (32494):         I/flutter (32494):        └─потомок 1: PhysicalModelLayer#edb15
  I/flutter (32494):           создатель: PhysicalModel  AnimatedPhysicalModel  Material 
  I/flutter (32494):             AnnotatedRegion<SystemUiOverlayStyle>  Semantics  AppBar 
  I/flutter (32494):             FlexibleSpaceBarSettings  ConstrainedBox  MediaQuery 
  I/flutter (32494):             LayoutId-[<_ScaffoldSlot.appBar>]  CustomMultiChildLayout 
  I/flutter (32494):             AnimatedBuilder  
  I/flutter (32494):           высота: 4.0
  I/flutter (32494):           цвет: MaterialColor(основное значение: Color(0xff2196f3))
  I/flutter (32494):          
  I/flutter (32494):          └─потомок 1: PictureLayer#418ce
  I/flutter (32494):              область рисования: Rect.fromLTBR(0.0, 0.0, 392.7, 83.6)
  I/flutter (32494):       
  I/flutter (32494):       └─потомок 3: TransformLayer#7f867
  I/flutter (32494):          смещение: Offset(0.0, 0.0)
  I/flutter (32494):          преобразование:
  I/flutter (32494):            [0] 1.0, 0.0, 0.0, -0.0
  I/flutter (32494):            [1] -0.0, 1.0, 0.0, 0.0
  I/flutter (32494):            [2] 0.0, 0.0, 1.0, 0.0
  I/flutter (32494):            [3] 0.0, 0.0, 0.0, 1.0
  I/flutter (32494):         
  I/flutter (32494):         └─потомок 1: PhysicalModelLayer#9f36b
  I/flutter (32494):            создатель: PhysicalShape  _MaterialInterior  Material 
  I/flutter (32494):              ConstrainedBox  _FocusMarker  Focus  _InputPadding 
  I/flutter (32494):              Semantics  RawMaterialButton  KeyedSubtree-[GlobalKey#9ead9]
  I/flutter (32494):               TickerMode  Offstage  
  I/flutter (32494):            выступание: 6.0
  I/flutter (32494):            цвет: Color(0xff2196f3)
  I/flutter (32494):           
  I/flutter (32494):           └─потомок 1: PictureLayer#2a074
  I/flutter (32494):               границы рисования: Rect.fromLTRB(320.7, 666.2, 376.7, 722.2)
  I/flutter (32494):  
  I/flutter (32494):  └─потомок 2: PictureLayer#3d42dI/flutter (32494):      границы рисования: Rect.  fromLTRB(0.0, 0.0, 1080.0, 2030.0)
I/flutter (32494): ```
Как можно заметить, в Flutter `Widget` в конечном итоге формирует различные `Layer`, каждый из которых имеет свой отдельный регион и функцию, например, `AnnotatedRegionLayer` управляет изменениями цвета состояния панели навигации на новых страницах, а эти `Layer` в конечном итоге преобразуются в `EngineLayer` с помощью `SceneBuilder`, который затем передается как `Scene` для отрисовки через движок.
Краткий вывод: **`Layer` в Flutter Framework до того, как они будут отрисованы, проходят через процесс обработки с использованием `SceneBuilder`, чтобы получить `EngineLayer`. Можно сказать, что `Layer` в Flutter Framework представляют собой объекты, упакованные внутри `SceneBuilder`, тогда как `EngineLayer` представляет собой реальные слои движка, которые затем становятся частью `Scene` для отрисовки через движок.**
> Таким образом, двадцать первая статья наконец завершена! (///▽///)
## Рекомендации по материалам
* Github: https://github.com/CarGuo
* **Открытый проект Flutter с полной реализацией: https://github.com/CarGuo/GSYGithubAppFlutter**
* **Открытый проект Flutter с множеством примеров: https://github.com/CarGuo/GSYFlutterDemo**
* **Открытая электронная книга по Flutter: https://github.com/CarGuo/GSYFlutterBook**
* Открытый проект React Native: https://github.com/CarGuo/GSYGithubApp
![Изображение](http://img.cdn.guoshuyu.cn/2bk20200327_Flutter-21/image7)

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master