1. Passing Functions Through Multiple Layers of Widgets
user들에게 MealDetails Screen 속의 item이 맘에 들면, favorite에 추가하는 기능을 만들어보자. 이때, 추가적인 기능을 어디에다가 사용할지가 관건인데, 이는 appBar속에 넣어보도록 하자.
일단, favorite star가 들어가야 할 곳은 당연히, ./screens/meal_details.dart에 지정해야 한다.(** mea_details.dart widget class는
각 meal의 detail을 담는 screen을 위한 widget이라는 것을 잊지말자.
**Step 01) AppBar 의 option인 actions에 다가 InconButton을 집어 넣도록 하자.
import 'package:flutter/material.dart';
import 'package:meals/models/meal.dart';
class MealDetailsScreen extends StatelessWidget{
const MealDetailsScreen({
super.key,
required this.meal,
});
final Meal meal;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text(meal.title),
actions:[
IconButton(
onPressed:(){} ,
icon: Icon(Icons.star))
]
)
**Step 02) MealDetails Class에서 favorite를 추가하면, 이를 받아서 궁금적으로 MealsScreen class로 전달해줘야 한다.
그런데,MealDateils의 favorite와 MealsScreen class의 중간역할을 하는 intermediary widget class라고 생각하고
코드를 작성해야 한다. 결론적으로, MealDetail에서 추천버튼을 눌렀을 때, Tab class의 _favoriateMeals의 list에서 더하 거나,빼지고 이 List자료구조를 MealsScreen으로 보내주면 된다는 말이다.
class TabsScreen extends StatefulWidget{
//생략
}
class _TabsScreen extends State<TabsScreen>{
int _selectedPageIndex=0;
//MealsDetails에서 추가한 meal을 담고 빼내는 자료구조 임.
final List<Meal>_favoriteMeals=[];
//추가적인 함수를 통해서 MealsDetail로 부터 받은 meal이 현재 Favorite에 있는지 확인. 있으면 빼고, 없으면 추가.
void _toggleMealFavoriteStatus(Meal meal){
//parameter로 받은 meal이 현재 _favoriteMeal에 있는지 체크
final isExisting=_favoriteMeals.contains(meal);
if(isExisting){
_favoriteMeals.remove(meal);
}else{
_favoriteMeals.add(meal);
}
}
**Step 03) Step02까지 _favoriteMeals 자료구조에 넣을 함수를 Tab Wiget class에 정의내렸다. 그렇다면, 이 정의된 함수를
활성화되는 곳은 MealsScreen이여야 한다. 즉, MealsScreen widget class가 _toggleMealFavoriteStatus를 받아들
일 수 있도록, 매개함수 하나를 추가해야 한다는 점이다.
이와 같이 MealDetails에서 meal을 parameter로 받는 function을 지정하고, 이 MealDetailsScreen이 사용되는 Widget class(/screens/meals.dart)로 돌아가서 추가적인 ontoggleFavorite function을 지정해준다.(hightligth 1번) 그리고 난 다음에 이 함수가 MealDetails widget class에서 star icon을 클릭했을 때, 활성화되게끔 해야 한다. (highligth 2번)
import 'package:flutter/material.dart';
import 'package:meals/models/meal.dart';
import 'package:meals/screens/meal_details.dart';
import 'package:meals/widget/meal_item.dart';
class MealsScreen extends StatelessWidget{
const MealsScreen({
super.key,
this.title,
required this.meals,
required this.ontoggleFavorite,
});
final String? title;
final List<Meal>meals;
final void Function(Meal meal) ontoggleFavorite;
void selectMeal(BuildContext context, Meal meal){
Navigator.of(context).push(
MaterialPageRoute(builder:
(ctx)=>MealDetailsScreen(
meal: meal,
ontoggleFavorite: ontoggleFavorite,)
));
}
**Step 04) Step03의 MealDetailsScreen의 변수를 조정하면 그 앞단의 Widget Class(MealsScreen/CategoriesScreen) 그리고 TabsScreen에도 영향을 받으므로 이를 조정해야 한다.
./screens/meals.dart 의 내용을 조정해야 함.
import 'package:flutter/material.dart';
import 'package:meals/models/meal.dart';
import 'package:meals/screens/meal_details.dart';
import 'package:meals/widget/meal_item.dart';
class MealsScreen extends StatelessWidget{
const MealsScreen({
super.key,
this.title,
required this.meals,
//highlight01) 추가함수변수 추가가
required this.ontoggleFavorite,
});
final String? title;
final List<Meal>meals;
final void Function(Meal meal) ontoggleFavorite;
void selectMeal(BuildContext context, Meal meal){
Navigator.of(context).push(
MaterialPageRoute(builder:
(ctx)=>MealDetailsScreen(
meal: meal,
//hightlight02) 적용해야함.
ontoggleFavorite: ontoggleFavorite,)
));
}
MealsScreen widget class를 변형했으므로, 다시 categoreis도 추가변경해야함.
./screens/categories.dart
import 'package:flutter/material.dart';
import 'package:meals/data/dummy_data.dart';
import 'package:meals/screens/meals.dart';
import 'package:meals/widget/category_grid_item.dart';
import 'package:meals/models/category.dart';
import 'package:meals/models/meal.dart';
class CategoriesScreen extends StatelessWidget{
const CategoriesScreen({super.key,required this.ontoggleFavorite});
//highlight01
final void Function(Meal meal) ontoggleFavorite;
void __selectCategory(BuildContext context,Category category){
final filterMeals=dummyMeals.where((meal)=>meal.categories.contains(category.id)).toList();
Navigator.of(context).push(
MaterialPageRoute(
builder: (context)=>MealsScreen(
title: 'Welcome to ${category.title} section',
meals: filterMeals,
//hightlight02
ontoggleFavorite:ontoggleFavorite,
) )
);
}
그리고 마지막으로 다시 /screens/tabs.dart로 돌아와서,Widget activePage=CategoriesScreen(ontoggleFavorite:_toggleMealFavoriteStatus,) 를 수정해주자.
import 'package:flutter/material.dart';
import 'package:meals/screens/categories.dart';
import 'package:meals/screens/meals.dart';
import 'package:meals/models/meal.dart';
//하나의 route에서 다른 route로 이동을 해야하므로, 우리는
//StatelessWidget이 아닌 StatefulWidget를 사용한다.
class TabsScreen extends StatefulWidget{
const TabsScreen({super.key});
@override
State<TabsScreen>createState(){
return _TabsScreen();
}
}
class _TabsScreen extends State<TabsScreen>{
int _selectedPageIndex=0;
final List<Meal>_favoriteMeals=[];
void _toggleMealFavoriteStatus(Meal meal){
//parameter로 받은 meal이 현재 _favoriteMeal에 있는지 체크
final isExisting=_favoriteMeals.contains(meal);
if(isExisting){
_favoriteMeals.remove(meal);
}else{
_favoriteMeals.add(meal);
}
}
var activePageTitle="Categories";
void _selectPage(int index){
setState((){
_selectedPageIndex=index;
});
}
@override
Widget build(BuildContext context){
Widget activePage=CategoriesScreen(ontoggleFavorite:_toggleMealFavoriteStatus,);
if(_selectedPageIndex==1){
activePage=MealsScreen(
meals:[],
ontoggleFavorite:_toggleMealFavoriteStatus,);
activePageTitle="Your favorite";
}
**5) MealsScreen의 meals option부분을 empty list가 아닌 _favoriteMeals로 전환하면, 이제 추가된 meal들이 스크린에 나오는 것을 허용한다.
./screens/tabs.dart에서 meals:_
if(_selectedPageIndex==1){
activePage=MealsScreen(
meals:_favoriteMeals,
ontoggleFavorite:_toggleMealFavoriteStatus,);
activePageTitle="Your favorite";
}
6) Favorite에 담겨진 meal에 있는 스타표시를 선택하면, 없어져야 하는데.. 그대로 favorite에 있는것을 알 수 있다.즉, 새로운 정보를 update해야하는데, 이게 반영되지 않는다는 반증인데. 이를 위핸선, setState()를 사용해야 한다. 이를 위해선, 아래와 같은 코드를 작성할 수 있다.
./screens/tabs.dart 파일에 아래와 같은 code lines를 집어넣는다.
class TabsScreen extends StatefulWidget{
const TabsScreen({super.key});
@override
State<TabsScreen>createState(){
return _TabsScreen();
}
}
class _TabsScreen extends State<TabsScreen>{
int _selectedPageIndex=0;
final List<Meal>_favoriteMeals=[];
void _toggleMealFavoriteStatus(Meal meal){
//parameter로 받은 meal이 현재 _favoriteMeal에 있는지 체크
final isExisting=_favoriteMeals.contains(meal);
if(isExisting){
setState(() {
_favoriteMeals.remove(meal);
});
}else{
setState(() {
_favoriteMeals.add(meal);
});
}
}
7) 그렇다면, snackBar라는 option을 통해서 우리가 전달하고자 하는 메시지를 인자로 주고, 그걸 snackBar에 보여주는 것을 목표로 한다.
1) _favoriteMeals에 meal을 추가할때,
"Marked as a favorite"메세지 보내기
2) _favoriteMeals에서 meal을 삭제할때,
"Meal is no longer a favorite"메시지 보내기
class _TabsScreen extends State<TabsScreen>{
int _selectedPageIndex=0;
final List<Meal>_favoriteMeals=[];
void _showInfoMessage(String message){
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
),
);
}
void _toggleMealFavoriteStatus(Meal meal){
//parameter로 받은 meal이 현재 _favoriteMeal에 있는지 체크
final isExisting=_favoriteMeals.contains(meal);
if(isExisting){
setState(() {
_favoriteMeals.remove(meal);
});
_showInfoMessage("Meal is no longer a favorite");
}else{
setState(() {
_favoriteMeals.add(meal);
});
_showInfoMessage("Marked as a favorite")
}
}
'Front-End > Flutter_Project_03_ToDo APP' 카테고리의 다른 글
8.Udemy 강의를 통한 Meals Project (0) | 2025.01.27 |
---|---|
7.Udemy 강의를 통한 Meals Project (0) | 2025.01.21 |
5. Udemy 강의를 통한 Meals Project (0) | 2025.01.19 |