-
Flutter_14. Theme in Widget & Dark Mode & Named Constructor & For in> Frontend/Flutter 2023. 5. 12. 20:25
0) 학습 내용
- main.dart에서 작성된 Theme 을 widget에서 사용
- Dark Mode
- Constructor ( named Constructor)
- For in
1) main.dart에서 작성된 Theme 을 widget에서 사용
... 생략 theme: ThemeData().copyWith( ... 생략
- main.dart에서 만들어진 theme 을 widget에서 사용해보기 (expenses_list.dart에서)
return Dismissible( key: ValueKey(expenses[index]), //create key obj background: Container(color: Theme.of(context).colorScheme.error.withOpacity(0.3), // setting up background color margin: EdgeInsets.symmetric(horizontal: Theme.of(context).cardTheme.margin!.horizontal), ), child: ExpenseItem(expense: expenses[index]), onDismissed: (direction) {
- main.dart에서 사용된 Theme of(context로 받아와), 해당 theme에 설정된 colorScheme 내에 error 색상으로 설정
- 동일하게, 설정된 cardTheme에서 설정된 margin값 가져와서 사용
cardTheme: const CardTheme().copyWith( color: kColorScheme.secondaryContainer, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8)),
- cardTheeme 내 margin의 horizontal은 16으로 설정되어 있음.
2) Dark Mode
import 'package:flutter/material.dart'; import 'package:flutter06_expense/widgets/expenses.dart'; // generates a color scheme based on a seed color var kColorScheme = ColorScheme.fromSeed( seedColor: const Color.fromARGB(255, 96, 59, 181), ); var kDarkColorScheme = ColorScheme.fromSeed( brightness: Brightness.dark, // need to set Brightness => otherwise, bright will be white seedColor: const Color.fromARGB(255, 5, 99, 125), ); void main() { runApp( MaterialApp( // copyWith: uses default useMaterial3 setting, no need to start from scratch // the theme of the MaterialApp by copying the default theme using ThemeData().copyWith() darkTheme: ThemeData.dark().copyWith( useMaterial3: true, colorScheme: kDarkColorScheme, cardTheme: const CardTheme().copyWith( color: kDarkColorScheme.secondaryContainer, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8)), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: kDarkColorScheme.primaryContainer, // primary container is the background color foregroundColor: kDarkColorScheme .onPrimaryContainer), //colors the content inside of that button: onPrimaryContainer ), ), theme: ThemeData().copyWith( useMaterial3: true, // add more settings below // 1. colorScheme colorScheme: kColorScheme, // 2. app-bar theme appBarTheme: const AppBarTheme().copyWith( backgroundColor: kColorScheme.onPrimaryContainer, // this foregroundColor will overwrite other foreground theme foregroundColor: kColorScheme.primaryContainer), cardTheme: const CardTheme().copyWith( color: kColorScheme.secondaryContainer, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8)), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: kColorScheme.primaryContainer), ), textTheme: ThemeData().textTheme.copyWith( titleLarge: TextStyle( fontWeight: FontWeight.w900, color: kColorScheme.onSecondaryContainer, fontSize: 20, ), )), themeMode: ThemeMode.light, // change material 2 to material3 home: const Expenses(), ), ); }
- main.dart.에 kDarkColorScheme을 설정해준다.
- 기존에 작성된 theme 위에 darkTheme 을 설정하고, 해당 theme에서 사용할 Theme을 설정한다.
- 이때, colorScheme: kDarkColorScheme으로 설정하여, fromSeed 를 통해 설정한 기본 color set으로 설정
themeMode: ThemeMode.light,
- 이후, 아래 쪽에 ThemeMode.system으로 설정하여, 기기의 설정에 따라 다르게 색상이 보여지도록 설정
- 위의 사진과 같이 dark mode 가 적용된다.
3) Constructor ( named Constructor)
- 인스턴스가 생성될 때, 호출되는 초기화 메소드
- 기본 생성자는 클래스의 이름과 같으며, 리턴값이 없고, 자동 생성된다.
- params를 전달해줄때는 따로 생성자를 생겅해야한다.
- Named Constructors를 사용하면, 하나의 클래스에 다양한 종류의 생성자를 생성할 수 있다.
- 클래스의 생성자 실행 순서로 초기화 목록 -> 상위 클래스의 기본 생성자 -> 하위 클래스의 기본 생성자.
- 초기화 목록(Initializer List)를 사용하면, 생성자 실행전에 변수 초기화 가능하고, 생성자 옆에 : 으로 시작하면 , 으로 구분
class ExpenseBucket { const ExpenseBucket({required this.category, required this.expenses}); // adding my own alternative names constructor // in order to filter out the expenses that belong to specific category // need initializer ExpenseBucket.forCategory(List<Expense> allExpenses, this.category) : expenses = allExpenses.where((expense) => expense.category == category).toList(); final Category category; final List<Expense> expenses; // adding getter double get totalExpenses { double sum = 0; for (final expense in expenses) { sum += expense.amount; } return sum; } }
- expense.dart에서 ExpenseBucket을 생성
- 해당 class 에서, forCategory라는 named constructor를 사용했는데, 초기화 목록을 사용하여, 우선순위 최상위에 넣어준다.
- 이 constructor는 받은 allExpenses 라는 값을 iterate하면서, 받은 category가 해당 파일에 생성된 expense.category 와 동일한지 확인하고, 동일한 경우, 아래 생성된 expenses에 넣어준다.
4) Code 추가 및 for in
import 'package:flutter/material.dart'; import 'package:flutter06_expense/widgets/chart/chart_bar.dart'; import 'package:flutter06_expense/models/expense.dart'; class Chart extends StatelessWidget { const Chart({super.key, required this.expenses}); final List<Expense> expenses; List<ExpenseBucket> get buckets { // helper getters return [ ExpenseBucket.forCategory(expenses, Category.food), ExpenseBucket.forCategory(expenses, Category.leisure), ExpenseBucket.forCategory(expenses, Category.travel), ExpenseBucket.forCategory(expenses, Category.work), ]; } double get maxTotalExpense { double maxTotalExpense = 0; for (final bucket in buckets) { if (bucket.totalExpenses > maxTotalExpense) { maxTotalExpense = bucket.totalExpenses; } } return maxTotalExpense; } @override Widget build(BuildContext context) { final isDarkMode = MediaQuery.of(context).platformBrightness == Brightness.dark; return Container( margin: const EdgeInsets.all(16), padding: const EdgeInsets.symmetric( vertical: 16, horizontal: 8, ), width: double.infinity, height: 180, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), gradient: LinearGradient( colors: [ Theme.of(context).colorScheme.primary.withOpacity(0.3), Theme.of(context).colorScheme.primary.withOpacity(0.0) ], begin: Alignment.bottomCenter, end: Alignment.topCenter, ), ), child: Column( children: [ Expanded( child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ for (final bucket in buckets) // alternative to map() ChartBar( fill: bucket.totalExpenses == 0 ? 0 : bucket.totalExpenses / maxTotalExpense, ) ], ), ), const SizedBox(height: 12), Row( children: buckets .map( (bucket) => Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: Icon( categoryIcons[bucket.category], color: isDarkMode ? Theme.of(context).colorScheme.secondary : Theme.of(context) .colorScheme .primary .withOpacity(0.7), ), ), ), ) .toList(), ) ], ), ); } }
- chart.dart
import 'package:flutter/material.dart'; class ChartBar extends StatelessWidget { const ChartBar({ super.key, required this.fill, }); final double fill; @override Widget build(BuildContext context) { final isDarkMode = // media query:: get environment information of which your app is running MediaQuery.of(context).platformBrightness == Brightness.dark; return Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: FractionallySizedBox( heightFactor: fill, child: DecoratedBox( decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: const BorderRadius.vertical(top: Radius.circular(8)), color: isDarkMode ? Theme.of(context).colorScheme.secondary : Theme.of(context).colorScheme.primary.withOpacity(0.65), ), ), ), ), ); } }
- chart_bar.dart
children: [ for (final bucket in buckets) // alternative to map() ChartBar( fill: bucket.totalExpenses == 0 ? 0 : bucket.totalExpenses / maxTotalExpense, ) ],
- for final expense in expenses, : 받아온 expenses에서 하나씩 iterate해서 나온 값을 기준으로 ChartBar에 보내준다.
List<ExpenseBucket> get buckets { // helper getters return [ ExpenseBucket.forCategory(expenses, Category.food), ExpenseBucket.forCategory(expenses, Category.leisure), ExpenseBucket.forCategory(expenses, Category.travel), ExpenseBucket.forCategory(expenses, Category.work), ]; }
- ExpenseBucket 에서 만들어진 named constructor 인 forCategory에 expenses 와 Category. * 을 전달
'> Frontend > Flutter' 카테고리의 다른 글
Flutter_16. Flutter Internals, Way of Render with Tree, Key, Mutating Values (0) 2023.05.16 Flutter_15. Building Responsive and adaptive User Interfaces (0) 2023.05.15 Flutter_14. Dropdown and Validation (0) 2023.05.09 Flutter_13. Dropdown and Validation (0) 2023.05.08 Flutter_12. DatePicker (0) 2023.05.06