首页/移动开发/flutter-theming-apps
F

flutter-theming-apps

by @flutterv
4.5(23)

讲解如何利用Flutter的主题系统定制应用视觉外观,确保品牌一致性和用户体验。

flutter-themingmaterial-designcustom-themesdark-modeui-customizationGitHub
安装方式
npx skills add flutter/skills --skill flutter-theming-apps
compare_arrows

Before / After 效果对比

1
使用前

在Flutter应用中修改视觉外观时,需要手动调整每个组件样式,耗时费力且容易不一致。应用风格难以统一,品牌形象受损。

使用后

利用Flutter主题系统,轻松定制应用视觉外观,实现全局统一风格。提升品牌一致性,简化样式管理,加速UI开发。

SKILL.md

Implementing Flutter Theming and Adaptive Design

Contents

Core Theming Concepts

Flutter applies styling in a strict hierarchy: styles applied to the specific widget -> themes that override the immediate parent theme -> the main app theme.

  • Define app-wide themes using the theme property of MaterialApp with a ThemeData instance.
  • Override themes for specific widget subtrees by wrapping them in a Theme widget and using Theme.of(context).copyWith(...).
  • Do not use deprecated ThemeData properties:
    • Replace accentColor with colorScheme.secondary.
    • Replace accentTextTheme with textTheme (using colorScheme.onSecondary for contrast).
    • Replace AppBarTheme.color with AppBarTheme.backgroundColor.

Material 3 Guidelines

Material 3 is the default theme as of Flutter 3.16.

  • Colors: Generate color schemes using ColorScheme.fromSeed(seedColor: Colors.blue). This ensures accessible contrast ratios.
  • Elevation: Material 3 uses ColorScheme.surfaceTint to indicate elevation instead of just drop shadows. To revert to M2 shadow behavior, set surfaceTint: Colors.transparent and define a shadowColor.
  • Typography: Material 3 updates font sizes, weights, and line heights. If text wrapping breaks legacy layouts, adjust letterSpacing on the specific TextStyle.
  • Modern Components:
    • Replace BottomNavigationBar with NavigationBar.
    • Replace Drawer with NavigationDrawer.
    • Replace ToggleButtons with SegmentedButton.
    • Use FilledButton for a high-emphasis button without the elevation of ElevatedButton.

Component Theme Normalization

Component themes in ThemeData have been normalized to use *ThemeData classes rather than *Theme widgets.

When defining ThemeData, strictly use the *ThemeData suffix for the following properties:

  • cardTheme: Use CardThemeData (Not CardTheme)
  • dialogTheme: Use DialogThemeData (Not DialogTheme)
  • tabBarTheme: Use TabBarThemeData (Not TabBarTheme)
  • appBarTheme: Use AppBarThemeData (Not AppBarTheme)
  • bottomAppBarTheme: Use BottomAppBarThemeData (Not BottomAppBarTheme)
  • inputDecorationTheme: Use InputDecorationThemeData (Not InputDecorationTheme)

Button Styling

Legacy button classes (FlatButton, RaisedButton, OutlineButton) are obsolete.

  • Use TextButton, ElevatedButton, and OutlinedButton.
  • Configure button appearance using a ButtonStyle object.
  • For simple overrides based on the theme's color scheme, use the static utility method: TextButton.styleFrom(foregroundColor: Colors.blue).
  • For state-dependent styling (hovered, focused, pressed, disabled), use MaterialStateProperty.resolveWith.

Platform Idioms & Adaptive Design

When building adaptive apps, respect platform-specific norms to reduce cognitive load and build user trust.

  • Scrollbars: Desktop users expect omnipresent scrollbars; mobile users expect them only during scrolling. Toggle thumbVisibility on the Scrollbar widget based on the platform.
  • Selectable Text: Web and desktop users expect text to be selectable. Wrap text in SelectableText or SelectableText.rich.
  • Horizontal Button Order: Windows places confirmation buttons on the left; macOS/Linux place them on the right. Use a Row with TextDirection.rtl for Windows and TextDirection.ltr for others.
  • Context Menus & Tooltips: Desktop users expect hover and right-click interactions. Implement Tooltip for hover states and use context menu packages for right-click actions.

Workflows

Workflow: Migrating Legacy Themes to Material 3

Use this workflow when updating an older Flutter codebase.

Task Progress:

  • 1. Remove useMaterial3: false from ThemeData (it is true by default).
  • 2. Replace manual ColorScheme definitions with ColorScheme.fromSeed().
  • 3. Run validator -> review errors -> fix: Search for and replace deprecated accentColor, accentColorBrightness, accentIconTheme, and accentTextTheme.
  • 4. Run validator -> review errors -> fix: Search for AppBarTheme(color: ...) and replace with backgroundColor.
  • 5. Update ThemeData component properties to use *ThemeData classes (e.g., cardTheme: CardThemeData()).
  • 6. Replace legacy buttons (FlatButton -> TextButton, RaisedButton -> ElevatedButton, OutlineButton -> OutlinedButton).
  • 7. Replace legacy navigation components (BottomNavigationBar -> NavigationBar, Drawer -> NavigationDrawer).

Workflow: Implementing Adaptive UI Components

Use this workflow when building a widget intended for both mobile and desktop/web.

Task Progress:

  • 1. If displaying a list/grid, wrap it in a Scrollbar and set thumbVisibility: DeviceType.isDesktop.
  • 2. If displaying read-only data, use SelectableText instead of Text.
  • 3. If implementing a dialog with action buttons, check the platform. If Windows, set TextDirection.rtl on the button Row.
  • 4. If implementing interactive elements, wrap them in Tooltip widgets to support mouse hover states.

Examples

Example: Modern Material 3 ThemeData Setup

MaterialApp(
  title: 'Adaptive App',
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.deepPurple,
      brightness: Brightness.light,
    ),
    // Use *ThemeData classes for component normalization
    appBarTheme: const AppBarThemeData(
      backgroundColor: Colors.deepPurple, // Do not use 'color'
      elevation: 0,
    ),
    cardTheme: const CardThemeData(
      elevation: 2,
    ),
    textTheme: const TextTheme(
      bodyMedium: TextStyle(letterSpacing: 0.2),
    ),
  ),
  home: const MyHomePage(),
);

Example: State-Dependent ButtonStyle

TextButton(
  style: ButtonStyle(
    // Default color
    foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
    // State-dependent overlay color
    overlayColor: MaterialStateProperty.resolveWith<Color?>(
      (Set<MaterialState> states) {
        if (states.contains(MaterialState.hovered)) {
          return Colors.blue.withOpacity(0.04);
        }
        if (states.contains(MaterialState.focused) || states.contains(MaterialState.pressed)) {
          return Colors.blue.withOpacity(0.12);
        }
        return null; // Defer to the widget's default.
      },
    ),
  ),
  onPressed: () {},
  child: const Text('Adaptive Button'),
)

Example: Adaptive Dialog Button Order

Row(
  // Windows expects confirmation on the left (RTL reverses the standard LTR Row)
  textDirection: Platform.isWindows ? TextDirection.rtl : TextDirection.ltr,
  mainAxisAlignment: MainAxisAlignment.end,
  children: [
    TextButton(
      onPressed: () => Navigator.pop(context, false),
      child: const Text('Cancel'),
    ),
    FilledButton(
      onPressed: () => Navigator.pop(context, true),
      child: const Text('Confirm'),
    ),
  ],
)

用户评价 (0)

发表评价

效果
易用性
文档
兼容性

暂无评价

统计数据

安装量9.5K
评分4.5 / 5.0
版本
更新日期2026年5月9日
对比案例1 组

用户评分

4.5(23)
5
48%
4
52%
3
0%
2
0%
1
0%

为此 Skill 评分

0.0

兼容平台

🔧Claude Code
🔧OpenClaw
🔧OpenCode
🔧Codex
🔧Gemini CLI
🔧GitHub Copilot
🔧Amp
🔧Kimi CLI

时间线

创建2026年3月16日
最后更新2026年5月9日