Irbisa · Шпаргалка
Темизация и дизайн-система
ThemeData, ColorScheme.fromSeed, Material 3, ThemeExtension, шрифты, тёмная тема
Как задать тему Flutter-приложению через
ThemeDataи как виджет её читает?class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return MaterialApp(…Что делает
ColorScheme.fromSeedи почему итоговыйprimaryне совпадает с вашим брендовым цветом?const brand = Color(0xFF00695C); final scheme = ColorScheme.fromSeed(seedColor: brand);// scheme.primary != brand: it is the palette tone that reads well on surface // When the literal brand colour is required…Что такое
TextThemeи зачем пользоваться его ролями вместоTextStyle, написанного на каждом экране?// before: one decision copied into every screenText('Monthly total', style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w600)); // after: a role the theme ownsText('Monthly total', style: Theme.of(context).textTheme.titleLarge);…Как добавить во Flutter-приложение свои шрифты и свои иконки?
# pubspec.yamlflutter: uses-material-design: true # the font behind Icons.* fonts: - family: Inter…Чем отличаются Material- и Cupertino-виджеты и можно ли использовать Cupertino-виджеты внутри
MaterialApp?Как поддержать светлую и тёмную тему через
theme,darkThemeиthemeMode?const _brand = Color(0xFF6750A4); ThemeData buildTheme(Brightness brightness) { final cs = ColorScheme.fromSeed(seedColor: _brand, brightness: brightness); return ThemeData( colorScheme: cs, // brightness comes from the scheme…Найдите баг: на некоторых телефонах белый логотип невидим на
AppBar, хотя приложение находится в светлой теме.class BrandLogo extends StatelessWidget { const BrandLogo({super.key}); @override Widget build(BuildContext context) { final isDark = MediaQuery.platformBrightnessOf(context) == Brightness.dark; return Image.asset( isDark ? 'assets/logo_white.png' : 'assets/logo_black.png', height: 24, ); }}Этот виджет строит
MaterialAppс брендовой темой, но прямоугольник закрашен дефолтным фиолетовым. Почему?class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { final primary = Theme.of(context).colorScheme.primary; return MaterialApp( theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF00695C)), ), home: ColoredBox(color: primary, child: const HomePage()), ); }}Найдите баг: после переключения на тёмную тему карточка становится тёмной, а цена на ней остаётся цвета светлой темы.
class _PriceTagState extends State<PriceTag> { late final TextStyle _priceStyle = Theme.of(context) .textTheme .headlineSmall! .copyWith(color: Theme.of(context).colorScheme.primary); @override Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.all(16), child: Text(widget.price, style: _priceStyle), ), ); }}В этом блоке хотели только красные кнопки, но текст потерял шрифт приложения, а обращение к
ThemeExtensionтеперь возвращает null. Что пошло не так?@overrideWidget build(BuildContext context) { return Theme( data: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.red), ), child: const DangerZone(), // buttons, text, BrandTokens.of(context) );}_canPayравен false, но кнопка всё равно закрашена брендовым цветом. Почему и как Material-кнопка определяет свой стиль?const brand = Color(0xFF00695C); FilledButton( onPressed: _canPay ? _pay : null, style: const ButtonStyle( backgroundColor: WidgetStatePropertyAll(brand), ), child: const Text('Pay'),);В дизайне Inter с весами 400, 500, 600 и 700, но на устройстве несколько весов выглядят одинаково. Что не так с настройкой шрифтов?
# pubspec.yaml: every weight the design uses is a declared fileflutter: fonts: - family: Inter fonts: - asset: assets/fonts/Inter-Regular.ttf # weight 400 by default…Что такое дизайн-токены и как примитивные и семантические токены ложатся на тему Flutter?
Что такое
ThemeExtensionи как добавить вThemeDataсвои токены, например цвет успеха или шаг отступа?@immutableclass BrandTokens extends ThemeExtension<BrandTokens> { const BrandTokens({required this.success, required this.gutter}); final Color success; final double gutter;…Что меняется при переходе приложения с Material 2 на Material 3 и что ломается так, что никто не замечает?
Как тема
MaterialAppдоходит до Cupertino-виджетов и когда нуженcupertinoOverrideTheme?final theme = ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF0B6E4F)), fontFamily: 'Inter', // Mainly brightness, primaryColor, primaryContrastingColor and // scaffoldBackgroundColor are derived from the Material theme above. cupertinoOverrideTheme: const CupertinoThemeData(…Как поддержать динамические цвета Material You на Android, сохранив брендовый запасной вариант, и когда от них стоит отказаться?
import 'package:dynamic_color/dynamic_color.dart'; const _brandSeed = Color(0xFF6750A4); class App extends StatelessWidget { const App({super.key});…Когда дизайн-системе стоит завести собственный
InheritedWidgetвместо того, чтобы класть значения вThemeExtension, и чем платят в каждом варианте?Как
MaterialAppанимирует смену темы и почему переключение в тёмный режим может моргнуть белым или заставить градиент прыгнуть?MaterialApp( theme: AcmeTheme.light(), darkTheme: AcmeTheme.dark(), themeMode: mode, // MaterialApp inserts AnimatedTheme; these are its knobs themeAnimationDuration: const Duration(seconds: 1), // slow it down to debug…Как построить один пакет дизайн-системы для нескольких приложений и поменять токен, ничего в них не сломав?
// packages/acme_design/lib/acme_design.dart: the whole public surfaceexport 'src/theme/acme_theme.dart' show AcmeTheme;export 'src/theme/acme_tokens.dart' show AcmeTokens, AcmeSpacing, AcmeContextX;export 'src/components/acme_empty_state.dart' show AcmeEmptyState; // lib/src/theme/acme_theme.dart…Как не дать сырым цветам и отступам вне шкалы снова расползтись по коду, где дизайн-система уже есть?
double contrast(Color a, Color b) { final la = a.computeLuminance(); final lb = b.computeLuminance(); final (hi, lo) = la > lb ? (la, lb) : (lb, la); return (hi + 0.05) / (lo + 0.05);}…Вам досталось приложение с 400 захардкоженными цветами и стилями текста, а заморозить релизы нельзя. Как перевести его на дизайн-систему?
// 1. inventory: grep -rEoh "Color\(0x[0-9A-Fa-f]{8}\)" lib | sort | uniq -c// 412 literals, 31 distinct values; 0xFFF5F5F5 and 0xFFF6F6F6 are one grey // 4. compat layer: nothing renders differently the day it lands,// and the analyzer now lists every remaining call site@Deprecated('Use context.acme.surfaceMuted; removed in app 4.0')…