[Flutter] provider 앱 구현

이제일·2021년 10월 5일
0

Flutter

목록 보기
5/6
post-thumbnail

공식 문서에서 상태관리를 설명을 위한 gif파일이 있습니다.

이번 장에서는 provider를 이용해서 이를 토대로 비슷하게 구현해보겠습니다.

클래스 요약


문서를 토대로 클래스간 관계를 설정했습니다. (MyAppBar는 없음)

관계도

클래스 설명

각 클래스의 책임

MyApp

  • 루트위젯
  • 복잡해지지않게 PageView를 이용해서 각 페이지 연결
  • Appbar와 debug표시 해제로 공간 확보
  • pageController를 static field로 둠으로써 각 페이지에서 화면 이동 구현

MyLoginScreen

  • 의미는 없는 화면 구성

MyCatalog

  • Appbar에서 기본아이콘인 장바구니를 다음 페이지로 이동하게 연결
  • A RenderFlex overflowed by ~~ pixels on the bottom.
    오류때문에 ListView로 각 아이템들(MyListItem)을 build

MyListItem

  • Container로 컬러박스 구현
  • MyCart의 itemList로 해당 아이템의 장바구니 여부에따라
    버튼을 add or ✔ 로 결정하기위해 select 사용
    (불필요한 rebuild 방지)
  • 버튼의 add의 경우 클릭 이벤트로 read를 사용해서 MyCart 업데이트

MyCart

  • itemList - 아이템 번호에 따라 장바구니 여부 저장
  • itemInfo - 컬러값과 가격을 고정해서 사용
  • addItem(), clearItem() - itemList를 변경 후 notifyListeners() 호출

완성된 어플

전체 예제 코드

main

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Cart(),
      child: const MyApp(),
    ),
  );
}

MyApp

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) :  super(key: key);
  static PageController pageController = PageController(initialPage: 0);

  static void previousPage() {
    pageController.previousPage(duration: kTabScrollDuration, curve: Curves.ease);
  }
  static void nextPage() {
    pageController.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
  }

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // debug 표시 해제
      home: Scaffold(
        body: PageView(
          scrollDirection: Axis.horizontal,
          controller: pageController,
          children:const <Widget>[
            MyLoginScreen(),
            MyCatalog(),
            MyCart()
          ],
        ),
      ),
    );
  }
}

MyLoginScreen

class MyLoginScreen extends StatelessWidget {
  const MyLoginScreen({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("Welcome")),
        body: Container(
          margin:const EdgeInsets.all(30),
          child:Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget> [
                const Text('Login',style: TextStyle(fontSize: 28)),
                const TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                  ),
                ),
                const Text('Password',style: TextStyle(fontSize: 28)),
                const TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                  ),
                ),
                ElevatedButton(onPressed: (){
                  FocusScope.of(context).unfocus();
                  MyApp.nextPage();},
                    child: const Text('Enter')),
              ])
        )
    );
  }
}

MyCatalog

class MyCatalog extends StatelessWidget {
  const MyCatalog ({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
      leading: IconButton(
        icon: const Icon(Icons.menu),
        onPressed: (){},
      ),
      actions: [
        IconButton(
          icon: const Icon(Icons.shopping_cart),
          onPressed: () {
            MyApp.nextPage();
          },
        ),
      ],
      title: const Text('Catalog'),
    ),
        body: ListView(children:[
          MyListItem(0),
          MyListItem(1),
          MyListItem(2),
          MyListItem(3),
          MyListItem(4)
    ]));
  }
}

MyListItem

class MyListItem extends StatelessWidget {
  int index;
  MyListItem(this.index, {Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    bool isIn = context.select((Cart cart) => cart.itemList[index]);
    TextButton button;

    if(isIn) {
      button = TextButton(
          child: const Icon(Icons.check,color: Colors.red),
          onPressed: (){}
      );
    }else {
      button = TextButton(
          child: const Text("add"), onPressed: (){
            context.read<Cart>().addItem(index);
          }
      );
    }

    return Row(children: [
          Container(width:150,height:50, margin:const EdgeInsets.all(10),color: Cart.itemInfo[index][0]),
          button
    ]);
  }
}

MyCart

class Cart extends ChangeNotifier {
  List itemList = [];
  Cart() : itemList = [false, false, false, false, false];

  static List itemInfo = [
    // 컬러값         가격
    [Colors.blue[100], (42*0.5).toInt()],
    [Colors.blue[300], 42],
    [Colors.blue[500], 42*2],
    [Colors.blue[700], 42*3],
    [Colors.blue[900], 42*4],
  ];

  void addItem(int index) {
    itemList[index] = true;
    notifyListeners();
  }

  void clearItem() {
    itemList = [false, false, false, false, false];
    notifyListeners();
  }
}
profile
세상 제일 이제일

0개의 댓글