This document describes the inner workings of the Flutter toolkit that make Flutter’s API possible. Because Flutter widgets are built using aggressive composition, user interfaces built with Flutter have a large number of widgets. To support this workload, Flutter uses sublinear algorithms for layout and building widgets as well as data structures that make tree surgery efficient and that have a number of constant-factor optimizations. With some additional details, this design also makes it easy for developers to create infinite scrolling lists using callbacks that build exactly those widgets that are visible to the user.
Flutter 내부
이 문서는 Flutter API를 가능하게하는 Flutter 툴킷의 내부 작업에 대해 설명합니다. Flutter 위젯은 적극적인 구성을 사용하여 구축되므로, Flutter로 구축된 사용자 인터페이스에는 많은 수의 위젯이 있습니다. 이 작업을 지원하기 위해 Flutter는 sublinear 알고리즘을 사용하여 레이아웃 및 위젯 빌드를 수행하며, 트리 수술을 효율적으로 수행하고 일부 상수 요소 최적화를 갖춘 데이터 구조를 사용합니다. 이 설계에 몇 가지 추가 세부 정보를 추가하면, 개발자가 콜백을 사용하여 사용자가 볼 수있는 정확히 그 위젯을 빌드하는 무한 스크롤링 목록을 쉽게 생성할 수도 있습니다.
One of the most distinctive aspects of Flutter is its aggressive composability. Widgets are built by composing other widgets, which are themselves built out of progressively more basic widgets. For example, Padding is a widget rather than a property of other widgets. As a result, user interfaces built with Flutter consist of many, many widgets.
The widget building recursion bottoms out in RenderObjectWidgets, which are widgets that create nodes in the underlying render tree. The render tree is a data structure that stores the geometry of the user interface, which is computed during layout and used during painting and hit testing. Most Flutter developers do not author render objects directly but instead manipulate the render tree using widgets.
In order to support aggressive composability at the widget layer, Flutter uses a number of efficient algorithms and optimizations at both the widget and render tree layers, which are described in the following subsections.
공격적인 구성성
Flutter의 가장 독특한 측면 중 하나는 그것의 공격적인 구성성입니다. 위젯은 다른 위젯을 조합하여 구축되며, 이 위젯들은 점차적으로 더 기본적인 위젯으로 구성됩니다. 예를 들어, Padding은 다른 위젯의 속성이 아닌 위젯입니다. 결과적으로, Flutter로 구축된 사용자 인터페이스는 많은 위젯으로 구성됩니다.
위젯 구축 재귀는 렌더 트리에서 노드를 생성하는 위젯인 RenderObjectWidgets에서 끝납니다. 렌더 트리는 사용자 인터페이스의 지오메트리를 저장하는 데이터 구조로, 레이아웃 중에 계산되고 페인트 및 히트 테스트 중에 사용됩니다. 대부분의 Flutter 개발자는 렌더 객체를 직접 작성하지 않고 위젯을 사용하여 렌더 트리를 조작합니다.
위젯 레이어에서 공격적인 구성성을 지원하기 위해 Flutter는 위젯 및 렌더 트리 레이어의 효율적인 알고리즘과 최적화를 사용합니다. 이러한 알고리즘과 최적화는 다음 하위 섹션에서 설명됩니다.
With a large number of widgets and render objects, the key to good performance is efficient algorithms. Of paramount importance is the performance of layout, which is the algorithm that determines the geometry (for example, the size and position) of the render objects. Some other toolkits use layout algorithms that are O(N²) or worse (for example, fixed-point iteration in some constraint domain). Flutter aims for linear performance for initial layout, and sublinear layout performance in the common case of subsequently updating an existing layout. Typically, the amount of time spent in layout should scale more slowly than the number of render objects.
Flutter performs one layout per frame, and the layout algorithm works in a single pass. Constraints are passed down the tree by parent objects calling the layout method on each of their children. The children recursively perform their own layout and then return geometry up the tree by returning from their layout method. Importantly, once a render object has returned from its layout method, that render object will not be visited again1 until the layout for the next frame. This approach combines what might otherwise be separate measure and layout passes into a single pass and, as a result, each render object is visited at most twice2 during layout: once on the way down the tree, and once on the way up the tree.
Flutter has several specializations of this general protocol. The most common specialization is RenderBox, which operates in two-dimensional, cartesian coordinates. In box layout, the constraints are a min and max width and a min and max height. During layout, the child determines its geometry by choosing a size within these bounds. After the child returns from layout, the parent decides the child’s position in the parent’s coordinate system3. Note that the child’s layout cannot depend on its position, as the position is not determined until after the child returns from the layout. As a result, the parent is free to reposition the child without needing to recompute its layout.
More generally, during layout, the only information that flows from parent to child are the constraints and the only information that flows from child to parent is the geometry. These invariants can reduce the amount of work required during layout: