ui-and-design

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Performance & Rendering

性能与渲染

  • Const-First: Every widget that can be
    const
    MUST be
    const
    .
  • Lazy Rendering: Mandatory use of lazy-loading constructs (
    SliverList.builder
    or
    SliverGrid.builder
    ) for any list exceeding 10 items.
  • Repaint Boundaries: Wrap complex animations or heavy UI sections in
    RepaintBoundary
    to optimize Impeller frame budget.
  • Isolate Parsing: Mandate
    compute()
    or
    Isolate
    for JSON parsing exceeding 1MB to avoid main-thread jank.
  • Optimize image handling with
    cached_network_image
  • Handle asynchronous operations cleanly with proper cancellation during widget disposal
  • Minimize unnecessary rebuilds using memoization techniques
  • Implement pagination for large data sets
  • Flatten widget hierarchies where reasonable for better rendering performance
  • BuildContext Safety: Check
    mounted
    before using
    context
    across async gaps to prevent
    setState
    after dispose.
  • Const优先:所有可以声明为
    const
    的widget必须声明为
    const
  • 懒渲染:任何超过10项的列表必须使用懒加载构造(
    SliverList.builder
    SliverGrid.builder
    )。
  • 重绘边界:将复杂动画或重度UI区块包裹在
    RepaintBoundary
    中,以优化Impeller帧预算。
  • 隔离解析:超过1MB的JSON解析必须使用
    compute()
    Isolate
    ,避免主线程卡顿。
  • 使用
    cached_network_image
    优化图片处理
  • 干净地处理异步操作,在widget销毁时正确取消异步任务
  • 使用记忆化技术减少不必要的重建
  • 针对大型数据集实现分页
  • 在合理范围内扁平化widget层级,以提升渲染性能
  • BuildContext安全:在异步间隙使用
    context
    前检查
    mounted
    状态,避免销毁后调用
    setState

Design System

设计系统

See design-system/SKILL.md for full token definitions (colors, spacing, radius, typography), reusable component rules, theming standards, and accessibility. Always use design tokens — never hardcode values.
完整的令牌定义(颜色、间距、圆角、排版)、可复用组件规则、主题标准和可访问性规范请查看design-system/SKILL.md。始终使用设计令牌,绝对不要硬编码数值。

Widget Patterns

Widget模式

  • Widget Extraction: STRICTLY prohibit private
    _build*()
    methods that return widgets. Extract them into separate
    StatelessWidget
    or
    StatefulWidget
    classes (can be private with
    _
    prefix). This ensures better testability, reusability, and composition.
  • Sliver Preference: Prefer
    CustomScrollView
    with
    Slivers
    over
    SingleChildScrollView
    for any non-trivial scrollable layout to ensure lazy loading and avoid jank. Use
    SliverList.builder
    or
    SliverList.separated
    and
    SliverGrid.builder
    for mixed content types.
  • Prominently use Sliver widgets:
    SliverAppBar
    ,
    SliverList
    ,
    SliverGrid
    ,
    SliverToBoxAdapter
    ,
    SliverPadding
    ,
    SliverPersistentHeader
    ,
    SliverFillRemaining
    ,
    SliverFixedExtentList
    ,
    SliverAnimatedList
    ,
    SliverFillViewport
    ,
    SliverOpacity
    ,
    SliverIgnorePointer
    ,
    SliverLayoutBuilder
    ,
    SliverPrototypeExtentList
    ,
    SliverVisibility
  • No Unnecessary Containers: Reduce usage of
    Container
    . Use chained widgets like
    DecoratedBox
    ,
    Padding
    ,
    SizedBox
    , etc. Prefer
    SizedBox
    over
    Container
    for simple spacing.
  • Use inbuilt animated widgets where applicable (
    AnimatedContainer
    ,
    AnimatedOpacity
    ,
    AnimatedSwitcher
    ,
    AnimatedPositioned
    , etc.) before resorting to explicit
    AnimationController
    .
  • Keep widgets focused and composable with clear responsibilities
  • Widget Keys: Assign
    Key('feature_action_id')
    to interactive widgets for test access. Use
    ValueKey(item.id)
    (not
    ValueKey(index)
    ) for list items.
  • Widget提取:严格禁止返回widget的私有
    _build*()
    方法。将它们提取为独立的
    StatelessWidget
    StatefulWidget
    类(可以用
    _
    前缀声明为私有)。这能保证更好的可测试性、可复用性和组合性。
  • 优先使用Sliver:对于任何非简单可滚动布局,优先使用带
    Slivers
    CustomScrollView
    而不是
    SingleChildScrollView
    ,以保证懒加载、避免卡顿。混合内容类型请使用
    SliverList.builder
    SliverList.separated
    SliverGrid.builder
  • 优先使用Sliver组件:
    SliverAppBar
    SliverList
    SliverGrid
    SliverToBoxAdapter
    SliverPadding
    SliverPersistentHeader
    SliverFillRemaining
    SliverFixedExtentList
    SliverAnimatedList
    SliverFillViewport
    SliverOpacity
    SliverIgnorePointer
    SliverLayoutBuilder
    SliverPrototypeExtentList
    SliverVisibility
  • 不要使用不必要的Container:减少
    Container
    的使用。使用链式组件如
    DecoratedBox
    Padding
    SizedBox
    等。简单间距优先使用
    SizedBox
    而不是
    Container
  • 适用场景下优先使用内置动画组件(
    AnimatedContainer
    AnimatedOpacity
    AnimatedSwitcher
    AnimatedPositioned
    等),再考虑显式使用
    AnimationController
  • 保持widget专注、可组合,职责清晰
  • Widget Key:为可交互组件分配
    Key('feature_action_id')
    以便测试访问。列表项使用
    ValueKey(item.id)
    (不要用
    ValueKey(index)
    )。

UI States

UI状态

  • Use a loading indicator while fetching data
  • Use an error indicator with appropriate messaging for error displays
  • Handle empty states gracefully in UI with clear messaging
  • 拉取数据时展示加载指示器
  • 错误展示时使用带合适提示文案的错误指示器
  • 优雅处理UI空状态,提供清晰的提示文案

Interaction Patterns

交互模式

  • FAB Usage: Use Floating Action Buttons (FAB) for primary positive actions (Add, Create, Generate, Save) on a screen. Avoid inline primary buttons when a FAB is more appropriate for the screen context.
  • Scroll Padding: ALWAYS add dynamic bottom padding to
    SliverList.builder
    or
    SingleChildScrollView
    when a FAB or Bottom Navigation Bar is present. Use
    MediaQuery.of(context).padding.bottom + kFloatingActionButtonMargin + 56
    (or
    AppSpacing.xxl
    ) to prevent content overlap.
  • Screen vs Sheet: Prefer full
    Scaffold
    screens over
    ModalBottomSheet
    for complex forms, especially those with text inputs, to ensure proper keyboard handling and deep linking capability.
  • Deep Linking: Complex flows should be addressable via deep links (e.g.,
    /strategy/:id
    instead of just a bottom sheet).
  • FAB使用规范:屏幕的主要正向操作(添加、创建、生成、保存)使用浮动操作按钮(FAB)。如果当前屏幕上下文更适合使用FAB,则避免使用行内主按钮。
  • 滚动内边距:当页面存在FAB或底部导航栏时,必须为
    SliverList.builder
    SingleChildScrollView
    添加动态底部内边距。使用
    MediaQuery.of(context).padding.bottom + kFloatingActionButtonMargin + 56
    (或
    AppSpacing.xxl
    )避免内容被遮挡。
  • 页面vs底部弹窗:复杂表单优先使用完整的
    Scaffold
    页面而不是
    ModalBottomSheet
    ,尤其是包含文本输入的表单,以保证正确的键盘处理和深度链接能力。
  • 深度链接:复杂流程应该可以通过深度链接访问(例如
    /strategy/:id
    ,而不是仅通过底部弹窗打开)。

Adaptive & Responsive Design

自适应与响应式设计

  • Design mobile first
  • Use
    LayoutBuilder
    and
    MediaQuery
    for adaptive layouts
  • Design for different screen sizes and orientations using responsive breakpoints
  • 优先设计移动端版本
  • 使用
    LayoutBuilder
    MediaQuery
    实现自适应布局
  • 使用响应式断点适配不同屏幕尺寸和方向

Adaptive Workflow (Abstract → Measure → Branch)

自适应工作流(抽象 → 测量 → 分支)

  1. Abstract: Identify widgets needing adaptability. Share common data (e.g.,
    Destination
    for both
    NavigationBar
    and
    NavigationRail
    ).
  2. Measure: Use
    MediaQuery.sizeOf(context)
    for app-level layout decisions;
    LayoutBuilder
    for widget-specific constraints.
  3. Branch: Apply breakpoints —
    < 600
    mobile,
    600–840
    tablet,
    >= 840
    desktop (Material guidelines).
  1. 抽象:识别需要适配的widget,共享通用数据(例如
    NavigationBar
    NavigationRail
    通用的
    Destination
    数据)。
  2. 测量:应用层级的布局决策使用
    MediaQuery.sizeOf(context)
    ;widget特定的约束使用
    LayoutBuilder
  3. 分支:应用断点规则——
    < 600
    为移动端,
    600–840
    为平板,
    >= 840
    为桌面端(Material设计规范)。

Adaptive Rules

自适应规则

  • Never lock orientation; support both portrait and landscape
  • Never use
    Platform.isIOS
    /
    Platform.isAndroid
    for layout decisions; use window size
  • Don't use
    OrientationBuilder
    for layout changes; use
    MediaQuery.sizeOf
    or
    LayoutBuilder
    with breakpoints
  • On large screens, avoid full-width content; constrain content width for readability
  • Support keyboard navigation, mouse hover effects, and focus handling for custom widgets
  • 永远不要锁定屏幕方向,同时支持竖屏和横屏
  • 永远不要使用
    Platform.isIOS
    /
    Platform.isAndroid
    做布局决策,使用窗口尺寸判断
  • 不要使用
    OrientationBuilder
    处理布局变化,使用
    MediaQuery.sizeOf
    或带断点的
    LayoutBuilder
  • 大屏设备上避免内容占满全宽,限制内容宽度以提升可读性
  • 自定义组件支持键盘导航、鼠标悬停效果和焦点处理