flutter

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Flutter

Flutter

Flutter is Google's UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase. It uses the Dart programming language and the Skia/Impeller graphics engine to render high-performance, pixel-perfect UIs.
Flutter是谷歌推出的UI工具包,可通过单一代码库构建原生编译的移动、网页和桌面应用。它采用Dart编程语言以及Skia/Impeller图形引擎,以渲染高性能、像素级完美的UI。

When to Use

适用场景

  • Building high-performance Android and iOS apps with a single codebase.
  • Creating custom, branded UI designs that need to look identical across platforms.
  • Developing prototypes or MVPs quickly with Hot Reload.
  • needing a solution that compiles to native code (ARM/x86) and WebAssembly.
  • 通过单一代码库构建高性能Android和iOS应用
  • 创建需要在各平台保持视觉一致的自定义品牌UI设计
  • 借助Hot Reload快速开发原型或最小可行产品(MVP)
  • 需要可编译为原生代码(ARM/x86)和WebAssembly的解决方案

Quick Start

快速开始

dart
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const MyApp());
}

// Router configuration
final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
    ),
  ],
);

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => CounterCubit(),
      child: MaterialApp.router(
        routerConfig: _router,
        theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.blue),
      ),
    );
  }
}

// Bloc/Cubit Logic
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  
  Widget build(BuildContext context) {
    // Access state via context.read/watch or BlocBuilder
    final count = context.select((CounterCubit cubit) => cubit.state);

    return Scaffold(
      appBar: AppBar(title: const Text('Flutter & Bloc')),
      body: Center(
        child: Text(
          'Count: $count',
          style: Theme.of(context).textTheme.headlineMedium,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterCubit>().increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}
dart
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const MyApp());
}

// 路由配置
final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
    ),
  ],
);

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => CounterCubit(),
      child: MaterialApp.router(
        routerConfig: _router,
        theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.blue),
      ),
    );
  }
}

// Bloc/Cubit 逻辑
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  
  Widget build(BuildContext context) {
    // 通过context.read/watch或BlocBuilder访问状态
    final count = context.select((CounterCubit cubit) => cubit.state);

    return Scaffold(
      appBar: AppBar(title: const Text('Flutter & Bloc')),
      body: Center(
        child: Text(
          'Count: $count',
          style: Theme.of(context).textTheme.headlineMedium,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterCubit>().increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

Core Concepts

核心概念

Widget Tree & Element Tree

组件树与元素树

Flutter uses a reactive style where the UI is built from a tree of immutable Widgets.
  • Widget: A configuration for an Element. Immutable description of part of the UI.
  • Element: An instantiation of a Widget at a particular location in the tree. Mutable manager of state and lifecycle.
  • RenderObject: The actual object that gets painted on the screen.
Flutter采用响应式风格,UI由不可变的Widget树构建而成。
  • Widget:Element的配置信息,是UI某一部分的不可变描述
  • Element:Widget在树中特定位置的实例,是状态和生命周期的可变管理器
  • RenderObject:实际绘制在屏幕上的对象

State Management (Bloc)

状态管理(Bloc)

Modern Flutter apps often use the Bloc (Business Logic Component) pattern for separation of concerns and predictable state.
  • Events: Inputs to the Bloc (e.g., button pressed).
  • States: Outputs from the Bloc (e.g., loading, data loaded).
  • Bloc/Cubit: The class that receives events and emits new states.
  • BlocBuilder: Widget that rebuilds in response to new states.
现代Flutter应用通常使用Bloc(业务逻辑组件)模式来实现关注点分离和可预测的状态管理。
  • Events:Bloc的输入(如按钮点击)
  • States:Bloc的输出(如加载中、数据已加载)
  • Bloc/Cubit:接收事件并发出新状态的类
  • BlocBuilder:响应新状态而重建的组件

Asynchronous Programming (Isolates)

异步编程(Isolates)

Dart is single-threaded but event-driven. Heavy computations should be moved to background Isolates to avoid blocking the UI thread (jank).
Dart是单线程但基于事件驱动的语言。繁重的计算任务应移至后台Isolates中执行,以避免阻塞UI线程(导致卡顿)。

Common Patterns

常见模式

Feature-First Architecture

功能优先架构

Organize files by feature rather than by layer.
text
lib/
  src/
    features/
      auth/
        data/
        domain/
        presentation/
          bloc/
          views/
      products/
    shared/
      components/
      constants/
    app.dart
    main.dart
按功能而非层级组织文件。
text
lib/
  src/
    features/
      auth/
        data/
        domain/
        presentation/
          bloc/
          views/
      products/
    shared/
      components/
      constants/
    app.dart
    main.dart

Clean Architecture with Repositories

结合仓库模式的整洁架构

  • Data Layer: Repositories, API clients (Dio/Http), DTOs.
  • Domain Layer: Entities, business logic (pure Dart).
  • Presentation Layer: Widgets, Blocs/Cubits.
  • 数据层:仓库、API客户端(Dio/Http)、数据传输对象(DTO)
  • 领域层:实体、业务逻辑(纯Dart实现)
  • 表示层:Widget、Bloc/Cubit

Best Practices

最佳实践

Do:
  • Use
    const
    constructors
    everywhere possible to optimize rebuilds.
  • Use
    GoRouter
    for deep linking and declarative navigation.
  • Use
    flutter_bloc
    to separate business logic from UI.
  • Use
    ThemeData
    and
    TextTheme
    for consistent styling.
Don't:
  • Don't put complex logic inside
    build()
    methods.
  • Don't misuse
    setState
    for complex global state.
  • Don't block the main thread; use
    compute()
    for heavy JSON parsing or calculations.
建议
  • 尽可能在所有地方使用
    const
    构造函数
    ,以优化重建性能
  • **使用
    GoRouter
    **实现深度链接和声明式导航
  • **使用
    flutter_bloc
    **分离业务逻辑与UI
  • **使用
    ThemeData
    **和
    TextTheme
    实现一致的样式
不建议
  • 不要在
    build()
    方法中放置复杂逻辑
  • 不要为复杂全局状态滥用
    setState
  • 不要阻塞主线程;对于繁重的JSON解析或计算,使用
    compute()

Troubleshooting

故障排查

| Error | Cause | Solution | 140: | :--------------------------------------------- | :--------------------------------------------- | :----------------------------------------------------------- | 141: |
RenderFlex overflowed by ... pixels
| Content is too wide/tall for the parent. | Wrap in
Expanded
,
Flexible
, or
SingleChildScrollView
. | 142: |
ProviderNotFoundException
| Reading a Bloc without a provider up the tree. | Ensure
BlocProvider
wraps the widget trying to access it. | 143: |
LateInitializationError
| Accessing a
late
variable before assignment. | Ensure generic initialization or use nullable types locally. | 144: |
Vertical viewport was given unbounded height
| ListView inside Column without constraints. | Wrap ListView in
Expanded
or
SizedBox
. |
错误原因解决方案
RenderFlex overflowed by ... pixels
内容对于父容器来说过宽/过高将内容包裹在
Expanded
Flexible
SingleChildScrollView
ProviderNotFoundException
在未向上查找树中存在的Provider的情况下读取Bloc确保
BlocProvider
包裹了尝试访问它的组件
LateInitializationError
在赋值前访问了
late
变量
确保通用初始化,或在本地使用可空类型
Vertical viewport was given unbounded height
Column中的ListView没有约束将ListView包裹在
Expanded
SizedBox

References

参考资料