ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter_14. Theme in Widget & Dark Mode & Named Constructor & For in
    > Frontend/Flutter 2023. 5. 12. 20:25

     

     

     

    0) 학습 내용

    1.  main.dart에서 작성된 Theme 을 widget에서 사용
    2.  Dark Mode
    3.  Constructor ( named Constructor)
    4.  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으로 설정하여, 기기의 설정에 따라 다르게 색상이 보여지도록 설정 

    DarkMode 적용 시,

    •  위의 사진과 같이 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. * 을 전달 

     

     

     

     

    댓글

Designed by Tistory.