Yaohong

为了真相不惜被羞辱

Constraint, Layout An Size On Flutter, Android, iOS And H5

In Flutter, the layout principle of “Constraints go down, Sizes go up, Parent sets position” is a clear and distinct mechanism for handling the layout of widgets. When comparing this with the layout mechanisms in Android, iOS, and HTML5/CSS/JS, we find different approaches and philosophies. Let’s compare these systems to understand their similarities and differences.

Layout and Size in Different Systems

Flutter

  • Constraints Go Down: Parent widgets send constraints to their children, specifying permissible sizes.
  • Sizes Go Up: Children choose their size within those constraints.
  • Parent Sets Position: Parents position children based on their size and constraints.

Android (View System)

  • Measure Phase:
    • Parent Determines Constraints: Parent views provide measurement specifications (MeasureSpec) to children.
    • Children Measure Size: Children determine their desired size based on these specifications, including modes (EXACTLY, AT_MOST, UNSPECIFIED).
  • Layout Phase:
    • Parent Sets Size and Position: Parents decide the final size and position of each child view using the layout() method, setting exact bounds within the parent’s coordinate system.

iOS (UIKit)

  • Constraints (Auto Layout):
    • Constraints Propagation: Constraints define relationships between views, such as size ratios or alignments.
    • Size Determination: Each view calculates its size based on these constraints and intrinsic content size.
  • Layout Passes:
    • Parent Resolves Constraints: Constraints are resolved to compute the frames (positions and sizes) of views.
    • Frames Set Position: The final position and size of each view are determined by resolving the constraints to specific frames.

HTML5/CSS/JS

  • CSS Box Model:
    • Constraints Through CSS: CSS rules (like width, height, max-width, min-width, etc.) define size constraints.
    • Size Computation: Elements calculate their size based on CSS rules, content size, and parent constraints.
  • Layout Mechanisms:
    • Flow Layout: Default document flow where elements take up available space in order.
    • Flexbox: Parent container defines constraints and alignment for flex items, which then size themselves within these constraints.
    • Grid Layout: Parent defines a grid structure, and child elements size and position themselves within grid areas.
  • Positioning:
    • CSS Positioning: Elements can be positioned using properties like position, top, left, right, and bottom, relative to their parent or document flow.

Comparison: Key Aspects

Constraints Handling

  • Flutter: Constraints explicitly passed from parent to child in a hierarchical manner.
  • Android: Constraints come from measure specs which include modes and sizes, less explicit than Flutter.
  • iOS: Constraints are set using Auto Layout, forming a constraint system that is resolved for size and position.
  • HTML/CSS: Constraints defined using CSS properties; more flexible and varied ways to specify constraints.

Size Determination

  • Flutter: Children determine size within provided constraints.
  • Android: Children measure themselves based on measure specs and report back desired sizes.
  • iOS: Size determined by solving constraints in Auto Layout system.
  • HTML/CSS: Size determined by CSS rules, intrinsic content, and parent constraints.

Positioning

  • Flutter: Parent sets position of children after size determination.
  • Android: Parent uses layout() method to set position within bounds.
  • iOS: Position determined by resolving constraints to frames.
  • HTML/CSS: Position determined by CSS properties and layout rules (flow, flexbox, grid).

Flexibility

  • Flutter: Clear and flexible constraint-based system.
  • Android: More rigid with fixed measure/layout phases.
  • iOS: Flexible but complex due to constraint-solving.
  • HTML/CSS: Highly flexible with multiple layout models (flow, flexbox, grid).

Examples

Flutter Example:

Container(
  constraints: BoxConstraints(
    minWidth: 100,
    maxWidth: 200,
  ),
  child: Text('Hello'),
)
  • Constraints: Container sends constraints to Text.
  • Size: Text chooses a size within constraints.
  • Position: Container sets the position of Text.

Android Example:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello"/>
</LinearLayout>
  • Constraints: LinearLayout provides measure specs to TextView.
  • Size: TextView measures itself based on specs.
  • Position: LinearLayout sets TextView’s position using layout().

iOS Example:

let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false

let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello"

container.addSubview(label)
NSLayoutConstraint.activate([
    label.widthAnchor.constraint(greaterThanOrEqualToConstant: 100),
    label.widthAnchor.constraint(lessThanOrEqualToConstant: 200),
    label.centerXAnchor.constraint(equalTo: container.centerXAnchor),
    label.centerYAnchor.constraint(equalTo: container.centerYAnchor)
])
  • Constraints: NSLayoutConstraint sets constraints on label.
  • Size: UILabel sizes itself based on constraints.
  • Position: Constraints determine UILabel’s position within container.

HTML/CSS Example:

<div style="display: flex; justify-content: center; align-items: center; width: 200px; height: 200px;">
  <div style="min-width: 100px; max-width: 200px;">
    Hello
  </div>
</div>
  • Constraints: CSS properties define constraints.
  • Size: Child div sizes itself based on min and max width.
  • Position: Parent div positions the child using flexbox.

Summary

The layout systems in Flutter, Android, iOS, and HTML5/CSS/JS each have their own approaches:


The Flutter Plugin Project Files

The Flutter Plugin Project Files

Creating the plugin project

$ flutter create --org com.example --template=plugin --platforms=android,ios,linux,macos,windows hello_plugin 

Signing iOS app for device deployment using developer identity: "Apple
Development: Yaohong Huang (WS3UUERGF9)"
Creating project hello_plugin...
Resolving dependencies in hello_plugin... (3.3s)
Got dependencies in hello_plugin.
Resolving dependencies in hello_plugin/example... (1.1s)
Got dependencies in hello_plugin/example.
Wrote 161 files.

All done!

Your plugin code is in hello_plugin/lib/hello_plugin.dart.

Your example app code is in hello_plugin/example/lib/main.dart.


Host platform code is in the android, ios, linux, macos, windows directories
under hello_plugin.
To edit platform code in an IDE see
https://flutter.dev/developing-packages/#edit-plugin-package.


To add platforms, run `flutter create -t plugin --platforms <platforms> .` under
hello_plugin.
For more information, see https://flutter.dev/go/plugin-platforms.
hello_plugin
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
│   ├── build.gradle
│   ├── hello_plugin_android.iml
│   ├── local.properties
│   ├── settings.gradle
│   └── src
│       ├── main
│       └── test
├── example
│   ├── README.md
│   ├── analysis_options.yaml
│   ├── android
│   │   ├── app
│   │   ├── build.gradle
│   │   ├── gradle
│   │   ├── gradle.properties
│   │   ├── gradlew
│   │   ├── gradlew.bat
│   │   ├── hello_plugin_example_android.iml
│   │   ├── local.properties
│   │   └── settings.gradle
│   ├── build
│   │   ├── 52f352800ae67b257006addf8ca3668f
│   │   ├── e29aedf18e567df5728f6b7ce57d2e97.cache.dill.track.dill
│   │   ├── ios
│   │   └── last_build_run.json
│   ├── hello_plugin_example.iml
│   ├── integration_test
│   │   └── plugin_integration_test.dart
│   ├── ios
│   │   ├── Flutter
│   │   ├── Podfile
│   │   ├── Podfile.lock
│   │   ├── Pods
│   │   ├── Runner
│   │   ├── Runner.xcodeproj
│   │   ├── Runner.xcworkspace
│   │   └── RunnerTests
│   ├── lib
│   │   └── main.dart
│   ├── linux
│   │   ├── CMakeLists.txt
│   │   ├── flutter
│   │   ├── main.cc
│   │   ├── my_application.cc
│   │   └── my_application.h
│   ├── macos
│   │   ├── Flutter
│   │   ├── Podfile
│   │   ├── Runner
│   │   ├── Runner.xcodeproj
│   │   ├── Runner.xcworkspace
│   │   └── RunnerTests
│   ├── pubspec.lock
│   ├── pubspec.yaml
│   ├── test
│   │   └── widget_test.dart
│   └── windows
│       ├── CMakeLists.txt
│       ├── flutter
│       └── runner
├── hello_plugin.iml
├── ios
│   ├── Assets
│   ├── Classes
│   │   └── HelloPlugin.swift
│   └── hello_plugin.podspec
├── lib
│   ├── hello_plugin.dart
│   ├── hello_plugin_method_channel.dart
│   └── hello_plugin_platform_interface.dart
├── linux
│   ├── CMakeLists.txt
│   ├── hello_plugin.cc
│   ├── hello_plugin_private.h
│   ├── include
│   │   └── hello_plugin
│   └── test
│       └── hello_plugin_test.cc
├── macos
│   ├── Classes
│   │   └── HelloPlugin.swift
│   └── hello_plugin.podspec
├── pubspec.lock
├── pubspec.yaml
├── test
│   ├── hello_plugin_method_channel_test.dart
│   └── hello_plugin_test.dart
└── windows
    ├── CMakeLists.txt
    ├── hello_plugin.cpp
    ├── hello_plugin.h
    ├── hello_plugin_c_api.cpp
    ├── include
    │   └── hello_plugin
    └── test
        └── hello_plugin_test.cpp
name: hello_plugin
description: A new Flutter plugin project.
version: 0.0.1
homepage:

environment:
  sdk: '>=3.0.5 <4.0.0'
  flutter: ">=3.3.0"

dependencies:
  flutter:
    sdk: flutter
  plugin_platform_interface: ^2.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:
  # This section identifies this Flutter project as a plugin project.
  # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
  # which should be registered in the plugin registry. This is required for
  # using method channels.
  # The Android 'package' specifies package in which the registered class is.
  # This is required for using method channels on Android.
  # The 'ffiPlugin' specifies that native code should be built and bundled.
  # This is required for using `dart:ffi`.
  # All these are used by the tooling to maintain consistency when
  # adding or updating assets for this project.
  plugin:
    platforms:
      android:
        package: com.example.hello_plugin
        pluginClass: HelloPlugin
      ios:
        pluginClass: HelloPlugin
      linux:
        pluginClass: HelloPlugin
      macos:
        pluginClass: HelloPlugin
      windows:
        pluginClass: HelloPluginCApi

The Widget tree, Element tree, and Rendering Object tree in flutter

The Widget tree, Element tree, Rendering Object tree in flutter

The purpose of the three type of trees in Flutter:

  • Widget tree:

    • 1.hold the widget config;
    • 2.offer a public API;
  • Element tree:

    • 1.manage the lifecycle of widget;
    • 2.hold a spot in the UI hierarchy;
    • 3.manage parent/child relationship;
  • Rendering object tree:

    • 1.layout, size and paint itself,
    • 2.layout children;
    • 3.claim input event;

Entry-point binding.dart

void runApp(Widget app){
    WidgetsFlutterBinding.ensureInitialized()
        ..attachRootWidget(app)
        ..scheduleWarmUpFrame();
}

Resouce: https://www.youtube.com/watch?v=996ZgFRENMs


The project files generated by 'flutter create --template=plugin_ffi' using dart:ffi to call C APIs

The project files generated by ‘flutter create –template=plugin_ffi’ using dart:ffi to call C APIs

Flutter mobile and desktop apps can use the dart:ffi library to call native C APIs.

Here are the project files generated by executing the following command:

flutter create --platforms=android,ios,macos,windows,linux --template=plugin_ffi native_add

flutter version: flutter_macos_3.10.5-stable

Reference:

Notes:

1.The FFI library can only bind against C symbols, so in C++ these symbols are marked extern “C”.