Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 앱번들
- Flutter #플러터 #프로젝트 #파이어베이스 #파이어스토어 #Firebase #FireStore
- 플러터 #Flutter #파이어베이스 #firebase #firestore #파이어스토어
- AAB
- Flutter #플러터 #모바일앱만들기 #GetX
- 복권번호예측 #Flutter #플러터 #Provider
- 유니티게임 #상점만들기 #뽑기구현 #케이디리듬게임
- 초성게임앱 #플러터앱 #플러터카운트다운
- flutter #android #androidstudio
- GetX #CustomScrollView #Flutter
- 플레이스토어 앱등록
- 복권번호예측기 #Flutter #adMob #광고배너 #리워드형광고
Archives
- Today
- Total
이코노딩
[Flutter] 내가 보려고 정리한 Provider 예시 본문
간단한 상태관리를 하기 위한 Provider 예시
1. ChangeNotifier 클래스 만들기
위젯에 쓰일 상태변경이 필요한 함수, 변수 등을 모아 클래스로 만들어 준다.
예를 들어 배달의 민족과 같은 앱을 모델로 생각했을 때,
장바구니로 기준을 잡고 모델을 구축한다.
장바구니에 필요한 모델
예시) 주문리스트, 부분선택 체크박스 리스트, 전체선택 값 등
▶Model
class Order{
String productName;
int price;
int count;
Order({
required this.price,
required this.productName,
required this.count,
});
}
▶Provider (ChangeNotifier은 with을 해도되고 extends해도된다 상황에 맞게 쓰기)
class TestProvider with ChangeNotifier{
List<Order> orderList = []; //주문리스트
List<bool> checkList = []; //주문리스트의 부분선택리스트
bool allCheck = true; //전체선택
void addOrder(Order order){
orderList.add(order); //장바구니 버튼을 누르면 오더리스트에 하나 넣기
checkList.add(true); //orderList 길이만큼 체크리스트도 필요함.
notifyListeners(); //상태 업데이트
}
void removeOrder(int index){
orderList.removeAt(index); //장바구니에서 삭제 버튼 누르면 해당 인덱스로 접근하여 삭제
checkList.removeAt(index); //체크리스트도 해당 인덱스 제거
notifyListeners(); //업데이트
}
void changeCheck(int index){
//체크박스누를 때 실행되는 함수 체크되있으면 해제, 해제되있으면 체크되게 조건문
checkList[index] ? checkList[index] = false : checkList[index] = true;
//전체선택 조건검사
if(checkList.contains(false) && allCheck){
//체크리스트에 false가있는데 전체 선택이 참인경우
allCheck = false; //전체선택을 꺼줌
}else if(checkList.every((element) => element == true) && !allCheck){
//체크리스트가 전부 true인데 전체선택이 꺼진경우
allCheck = true; //전체선택 켜기
}
notifyListeners();//업데이트
}
void changeAllCheck(){
//전체선택을 눌렀을 때
if(allCheck){
allCheck = false;
//체크리스트 아이템들을 전부 false로 바꾼후 checkList에 넣기
checkList = checkList.map((e) => e = false).toList();
}else{
allCheck = true;
checkList = checkList.map((e) => e = true).toList();
}
notifyListeners(); //업데이트
}
void pressBuyBtn(){
List<Order> buyList = []; //최종구매리스트
//최종 구매하기 버튼 클릭시, 체크되어있는 부분만 확인하기
for(var i = 0; i<checkList.length; i++){
//체크리스트 인덱스 중 참인경우에만 최종구매리스트에 넣어줌
if(checkList[i]){
buyList.add(orderList[i]);
}
}
}
}
2. main.dart 최상위에 create하기
최상위에 해야하는 이유 https://iconoding.tistory.com/38 참고
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
//Provider를 여러개 쓰는 경우 MultiProvider 근데 보통 하나의 앱에 프로바이더는 수두룩하게 쓰이니까...
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_)=> TestProvider()),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const TestPage(title: 'Provider Demo Test Page'),
),
);
}
}
이제 위젯에 가져다 쓰기만 하면된다.
3. Widget만들기
class TestPage extends StatefulWidget {
const TestPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<TestPage> createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
//프로바이더 선언시 context가 필요하므로 나중에 넣어주기
late TestProvider testProvider;
@override
Widget build(BuildContext context) {
testProvider = Provider.of<TestProvider>(context);
return Scaffold(
appBar: AppBar(
toolbarHeight: 52,
title: Text(widget.title),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
child: CustomScrollView(
slivers: [
//비어있니?
testProvider.orderList.isEmpty ?
const SliverToBoxAdapter() : SliverToBoxAdapter(
child: Row(children: [
Checkbox(value: testProvider.allCheck, onChanged: (value) => testProvider.changeAllCheck()),
const Text('전체선택')
],),
),
testProvider.orderList.isEmpty ?
SliverToBoxAdapter(
child: SizedBox(
height: MediaQuery.of(context).size.height - 52,
width: MediaQuery.of(context).size.width - 52,
child: const Center(child: Text('장바구니 비어있음'),),
),
) :
SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
childCount: testProvider.orderList.length,
(context, index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Checkbox(value: testProvider.checkList[index], onChanged: (value) => testProvider.changeCheck(index),),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(testProvider.orderList[index].productName),
Text('${testProvider.orderList[index].price}원'),
Text('${testProvider.orderList[index].count}개')
],
),
IconButton(onPressed: ()=> testProvider.removeOrder(index), icon: const Icon(Icons.delete))
],
),
),
itemExtent: 100),
testProvider.orderList.isEmpty ?
const SliverToBoxAdapter() : SliverToBoxAdapter(
child: ElevatedButton(
child: const Text('구매하기'),
onPressed: ()=> testProvider.pressBuyBtn(),
),
)
],
),
),
);
}
}
Widget을 만들고 Provider.of(context)로 접근하여 사용하면된다.
아니면 <T>는 Provider
✅ context.read<T>() //상태변화를 읽지는 않고 메소드에 접근할 때 사용
✅ context.watch<T>() //상태변화를 읽음
를 사용하면 된다.
결과
동작하는데 문제는 없다.
삭제되었을때도 전체선택 검사가 필요해 보인다.
▶ Consumer사용하기
Context를 사용하지 않고 Provider를 사용할 수 있게해주는 위젯이다.
Stateless를 사용하고 가벼운 상태변경에 쓰거나 화면구성중 작은 부분만 변경할 때, 사용하기 좋을 것 같다.
class ConsumerTestPage extends StatelessWidget {
const ConsumerTestPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 52,
title: Text(title),
centerTitle: true,
),
body: Consumer<TestProvider>(
builder: (context, provider, widget){
if(provider.orderList.isEmpty){
return SizedBox(
height: MediaQuery.of(context).size.height -52,
width: MediaQuery.of(context).size.width,
child: const Center(child: Text('장바구니 비어있음'),),
);
}else{
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Row(children: [
Checkbox(value: provider.allCheck, onChanged: (value) => provider.changeAllCheck()),
const Text('전체선택')
],),
),
SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
childCount: provider.orderList.length,
(context, index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Checkbox(value: provider.checkList[index], onChanged: (value) => provider.changeCheck(index),),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(provider.orderList[index].productName),
Text('${provider.orderList[index].price}원'),
Text('${provider.orderList[index].count}개')
],
),
IconButton(onPressed: ()=> provider.removeOrder(index), icon: const Icon(Icons.delete))
],
),
),
itemExtent: 100),
SliverToBoxAdapter(
child: ElevatedButton(
child: const Text('구매하기'),
onPressed: ()=> provider.pressBuyBtn(),
),
)
],
);
}
},
),
);
}
}
동작은 위 이미지와 똑같이 잘 동작함
Git: https://github.com/Inhochoi0201/ProviderSample
'언어 > Dart & Flutter' 카테고리의 다른 글
[Flutter] GetX로 상태관리하기 (0) | 2023.01.04 |
---|---|
[Flutter] 내가 보려고 정리한 Scroll Physics (0) | 2022.12.20 |
[Flutter] connectivity_plus 네트워크 상태 읽기 (0) | 2022.11.21 |
Flutter Project : 오프라인 게임 지원 앱 만들기 -4 (0) | 2022.06.07 |
Flutter Project : 오프라인 게임 지원앱 만들기 -3 (0) | 2022.06.06 |