ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [FLUTTER] 상태 관리 패키지 (Provider) 적용하기
    Flutter 2023. 4. 9. 18:46

    [버킷 리스트 조회 (Read) 기능]

    : BucketService에 있는 bucketList 값을 가져와서 HomePage에 보여줘야 하는데, Consumer 위젯을 이용하면 위젯트리 꼭대기에 등록된 BucketService에 접근할 수 있다.

    Consumer<BucketService>( // 찾고자하는 클래스의 이름을 적어주면 됨 (BucketService)
    	builder: (context, bucketService, child) { // 받을 변수의 이름 (마음대로 바꿔도 상관없음) : bucketService
    		return 위젯;
    	}
    )
    • Consumer<BucketService> : 위젯트리 상단에서 찾아올 클래스 이름을 <>사이에 적는다.
    • builder: (context, bucketService, child) { return 위젯; } : 화면에 보여줄 위젯을 반환하는 함수로, 위젯트리 상단에서 찾아온 클래스를 두 번째 파라미터로 받을 수 있다.

    Consumer<BucketService>는 위젯 트리를 타고 올라가 Provider로 등록된 BucketService를 찾고, 찾은 BucketService를 bucketService라는 이름을 가진 두 번째 파라미터로 전달해 준다.

     

    BucketService에서 값이 변경되는 경우, StatefulWidgetsetState와 같이 notifyListeners();를 호출하는데, 이 때 해당 서비스를 Consumer로 등록된 모든 위젯의 builder 함수가 재호출 되면서 화면이 갱신된다.

    class HomePage extends StatelessWidget {
      const HomePage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Consumer<BucketService>(builder: (context, bucketService, child) {
        // bucketService로 부터 bucketList 가져오기
          List<Bucket> bucketList = bucketService.bucketList;
          return Scaffold(
            appBar: AppBar(
              title: Text("버킷 리스트"),
            ),
            body: Center(child: Text("버킷 리스트를 작성해 주세요.")),
            floatingActionButton: FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                // + 버튼 클릭시 버킷 생성 페이지로 이동
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (_) => CreatePage()),
                );
              },
            ),
          );
        });
      }
    }

     

    bucketList 보여주기

    : bucketList를 HomePage가 아닌 BucketService 가져오는 점에서 이전 프로젝트와 다르다!

    body: bucketList.isEmpty
                  ? Center(child: Text("버킷 리스트를 작성해 주세요."))
                  : ListView.builder(
                      itemCount: bucketList.length, // bucketList 개수 만큼 보여주기
                      itemBuilder: (context, index) {
                        var bucket = bucketList[index]; // index에 해당하는 bucket 가져오기
                        return ListTile(
                          // 버킷 리스트 할 일
                          title: Text(
                            bucket.job,
                            style: TextStyle(
                              fontSize: 24,
                              color: bucket.isDone ? Colors.grey : Colors.black,
                              decoration: bucket.isDone
                                  ? TextDecoration.lineThrough
                                  : TextDecoration.none,
                            ),
                          ),
                          // 삭제 아이콘 버튼
                          trailing: IconButton(
                            icon: Icon(CupertinoIcons.delete),
                            onPressed: () {
                              // 삭제 버튼 클릭시
                            },
                          ),
                          onTap: () {
                            // 아이템 클릭시
                          },
                        );
                      },
                    ),

     

    [버킷 리스트 생성 (Create) 기능]

    : 기존과 달리 CreatePage와 HomePage 간 데이터를 주고받지 않고, CreatePage에서 곧 바로 BucketServicejob을 넘겨주는 방식으로 구현

     

    BucketService에 Bucket을 추가하는 함수를 구현
    • bucket_service.dart
      /// bucket 추가
      void createBucket(String job) {
        bucketList.add(Bucket(job, false));
      }

    : BucketServicebucketList에 대한 CRUD 기능을 담당하는 함수를 추가할 예정, 그 중 Create를 담당하는 createBucket 함수를 생성

     

    CreatePage에서 추가하기 버튼 클릭시, BucketService에 방금 만든 createBucket함수를 호출

    추가하기 버튼을 누를 때 기존에는 jobNavigator.pop(context, job);을 이용해서 HomePage로 넘겨주었지만 이번에는 BucketService 에 접근해서 createBucket() 함수로 job을 넘겨주어 버킷 리스트를 추가!

     

    context.read<클래스명>();를 이용하면 위젯 트리 상단에 있는 Provider로 등록한 클래스에 접근할 수 있다.

    // BucketService 가져오기
     BucketService bucketService = context.read<BucketService>();
     bucketService.createBucket(job);
    • main
    /// 버킷 생성 페이지
    class CreatePage extends StatefulWidget {
      const CreatePage({Key? key}) : super(key: key);
    
      @override
      State<CreatePage> createState() => _CreatePageState();
    }
    
    class _CreatePageState extends State<CreatePage> {
      // TextField의 값을 가져올 때 사용합니다.
      TextEditingController textController = TextEditingController();
    
      // 경고 메세지
      String? error;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("버킷리스트 작성"),
            // 뒤로가기 버튼
            leading: IconButton(
              icon: Icon(CupertinoIcons.chevron_back),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ),
          body: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                // 텍스트 입력창
                TextField(
                  controller: textController,
                  autofocus: true,
                  decoration: InputDecoration(
                    hintText: "하고 싶은 일을 입력하세요",
                    errorText: error,
                  ),
                ),
                SizedBox(height: 32),
                // 추가하기 버튼
                SizedBox(
                  width: double.infinity,
                  height: 48,
                  child: ElevatedButton(
                    child: Text(
                      "추가하기",
                      style: TextStyle(
                        fontSize: 18,
                      ),
                    ),
                    onPressed: () {
                      // 추가하기 버튼 클릭시
                      String job = textController.text;
                      if (job.isEmpty) {
                        setState(() {
                          error = "내용을 입력해주세요."; // 내용이 없는 경우 에러 메세지
                        });
                      } else {
                        // 사용자가 글을 입력한 경우에 누르는 시점에 실행되는 부분
                        setState(() {
                          error = null; // 내용이 있는 경우 에러 메세지 숨기기
                        });
                        // BucketService 가져오기
                        BucketService bucketService = context.read<BucketService>();
                        bucketService.createBucket(job);
                        Navigator.pop(context); // 화면을 종료합니다.
                      }
                    },
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    • bucket_service.dart
    import 'package:flutter/material.dart';
    
    import 'main.dart';
    
    /// Bucket 담당
    class BucketService extends ChangeNotifier {
      // 변경된사항을 알려준다 (notifier)
      List<Bucket> bucketList = [
        Bucket('잠자기', false), // 더미(dummy) 데이터
      ];
    
      /// bucket 추가
      void createBucket(String job) {
        // create화면에서 추가하기 버튼을 누를때 호출할것
        bucketList.add(Bucket(job, false));
        
        notifyListeners(); // 갱신 = Consumer<BucketService>의 builder 부분만 새로고침
      }
    }

    : bucket_service.dart에 notifyListeners();를 붙여주지않으면 생성되지않는다.

    why? job을 추가 했지만, HomePage에 아무런 변화가 없는 이유는 BucketService에 신규 버킷이 추가 되었지만 HomePage 화면이 갱신되지 않았기 때문!

    → BucketService에서 notifyListeners();를 호출하면 모든 Consumer<BucketService>builder 파라미터의 함수를 호출해 화면을 갱신해 준다!

     

    이 기능은 BucketServiceChangeNotifier 클래스 기능을 그대로 물려받고, main.dart 11번째 줄에 Provider로 등록시 변경사항 알람을 보낼 수 있는 ChangeNotifierProvider로 등록 된 경우에만 이용할 수 있다!

    • main.dart

    • bucket_service.dart

    [버킷 리스트 수정 (Update) 기능]

    : 버킷의 상태가 변하는 경우 화면을 갱신하기 위해 notifyListeners()를 호출

    /// bucket 수정
      void updateBucket(Bucket bucket, int index) {
        // index에 해당되는 bucketList에 전달받은 bucket을 넣는 방식으로 update
        bucketList[index] = bucket;
        // 버킷의 상태가 변하는 경우 화면을 갱신하기 위해 notifyListeners()를 호출
        notifyListeners();
      }
    ListTile을 클릭하는 경우, isDone 상태를 변경
    bucket.isDone = !bucket.isDone;
    bucketService.updateBucket(bucket, index);
    • main

    : 아이템을 클릭했을때, 선이 그어지도록 (다시 클릭하면 지워지도록 - Toggle)

    onTap: () {
                          // 아이템 클릭시
                          bucket.isDone = !bucket.isDone;
                          bucketService.updateBucket(bucket, index);
                        },

    [버킷 리스트 삭제 (Delete) 기능]

    : 버킷을 삭제하는 경우, 화면이 갱신되어야 하므로 notifyListners();를 호출

    /// bucket 삭제
      void deleteBucket(int index) {
        bucketList.removeAt(index);
        notifyListeners();
      }
    • main

    : 삭제 아이콘 버튼을 눌렀을경우 해당 index 데이터 삭제! 

    // 삭제 아이콘 버튼
                        trailing: IconButton(
                          icon: Icon(CupertinoIcons.delete),
                          onPressed: () {
                            // 삭제 버튼 클릭시
                            bucketService.deleteBucket(index);
                          },
                        ),

     

Designed by Tistory.