1. Updating MealDeatilScreen
Category---> MealScreen ---> MealDatilsScreen으로 차례대로 코딩을 진행하였다.이때, MealDetailsScreen에는 위에 보이는 것처럼 이미지밖에 나오지 않도록 코드를 작성했는데, 이를 코드를 추가하여 , 음식성분 등 음식에 대한 세부정보를 추가하도록 하자.
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),
),
body:Column(
children: [
//image
Image.network(
meal.imageUrl,
height:300,
width:double.infinity,
fit:BoxFit.cover,
),
const SizedBox(height: 14,),
//ingradients-title
Text(
'Ingredients',
style:Theme.of(context).textTheme.titleLarge!.copyWith(
color:Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
)
),
const SizedBox(height: 14,),
//ingradients-contents
for(final ingradient in meal.ingredients)
Text(ingradient,
style:Theme.of(context).textTheme.titleMedium!.copyWith(
color:Theme.of(context).colorScheme.onSurface
)),
const SizedBox(height:14,),
//steps-title
Text('Steps',
style:Theme.of(context).textTheme.titleLarge!.copyWith(
color:Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
)),
//steps-contents
for(final step in meal.steps)
Text(
step,
textAlign: TextAlign.center,
style:Theme.of(context).textTheme.bodyMedium!.copyWith(
color:Theme.of(context).colorScheme.onSurface
)
)
],
)
위 사진을 보면, steps에 간격이 너무 좋아서 가독성이 떨어지므로, 우리는 padding option을 집어넣기로 하자.
for(final step in meal.steps)
Padding(
padding:const EdgeInsets.symmetric(
horizontal: 12,
vertical:6),
child:Text(
step,
textAlign: TextAlign.center,
style:Theme.of(context).textTheme.bodyMedium!.copyWith(
color:Theme.of(context).colorScheme.onSurface
)
)
이와 같이 padding을 넣어주면, 범위의 관련된 오류가 발생한다.
위와 같은 오류는 현재 widget이 scrollable하지 않기 때문에, 나오는 오류이다. 이를 수정하기 위해선, 우리는 ListView 또는 SingleChildScrollView를 사용한다. 전체 코드는 아래와 같다.
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),
),
body:SingleChildScrollView(
child: Column(
children: [
//image
Image.network(
meal.imageUrl,
height:300,
width:double.infinity,
fit:BoxFit.cover,
),
const SizedBox(height: 14,),
//ingradients-title
Text(
'Ingredients',
style:Theme.of(context).textTheme.titleLarge!.copyWith(
color:Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
)
),
const SizedBox(height: 14,),
//ingradients-contents
for(final ingradient in meal.ingredients)
Text(ingradient,
style:Theme.of(context).textTheme.titleMedium!.copyWith(
color:Theme.of(context).colorScheme.onSurface
)),
const SizedBox(height:14,),
//steps-title
Text('Steps',
style:Theme.of(context).textTheme.titleLarge!.copyWith(
color:Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
)),
//steps-contents
for(final step in meal.steps)
Padding(
padding:const EdgeInsets.symmetric(
horizontal: 12,
vertical:6),
child:Text(
step,
textAlign: TextAlign.center,
style:Theme.of(context).textTheme.bodyLarge!.copyWith(
color:Theme.of(context).colorScheme.onSurface
)
)
)
],
),
)
);
}
}
2. Adding Tab-based Navigation
공식문서에서 tab-based navigation을 아래와 같이 설명한다.
"Possibly the most common style of navigation in mobile apps is tab-based navigation. This module can manage the tabs on the screen."
/screens/tabs.dart 파일에 다가, 아래와 같이 코드를 작성한다.
import 'package:flutter/material.dart';
import 'package:meals/screens/categories.dart';
import 'package:meals/screens/meals.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;
var activePageTitle="Categories";
void _selectPage(int index){
setState((){
_selectedPageIndex=index;
});
}
@override
Widget build(BuildContext context){
Widget activePage=const CategoriesScreen();
if(_selectedPageIndex==1){
activePage=MealsScreen(title: 'Favorites', meals:[]);
activePageTitle="Your favorite";
}
return Scaffold(
appBar:AppBar(
title:Text(activePageTitle),
),
body:activePage,
bottomNavigationBar:BottomNavigationBar(
onTap:_selectPage,
currentIndex: _selectedPageIndex,
items:const [
BottomNavigationBarItem(icon:Icon(Icons.set_meal),label:"Categories"),
BottomNavigationBarItem(icon:Icon(Icons.start),label:"Favorite"),
]
),
);
}
}
그리고 main.dart에 다가
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: theme,
home:const TabsScreen() ,
);
}
}
두개의 tapbar를 사용하니깐,사실상 design 측면에선 사실 미흡하다는 생각이 든다. 이때는, 단순히 ./screens/categories.dart에서 appBar를 지운다.
tab이 보이지 않는 문제점이 있다. 예를들어, category를 select했는데 위에 이미지처럼 tab이 보이지 않는 문제점이 발생한다. 그렇다면, 이를 어떻게 관리해야할까?
./screens/meals.dart로 이동해서, MealsScreen의 멤버변수인 title을 required에서 null 값을 포함한 값으로 바꾼다.
class MealsScreen extends StatelessWidget{
const MealsScreen({
super.key,
this.title,
required this.meals
});
final String? title;
final List<Meal>meals;
if(title==null){
return content;
}
return Scaffold(
appBar:AppBar(
title:Text(title!),
),
//ListViewBuilder
//itemCount만큼, itemBuilder를 실행시켜 widget를 반환
body: content,
);
}
마지막으로 ./screens/tabs.dart로 가서, 아래와 같이 MealsScreen에서 title을 빼준다.
import 'package:flutter/material.dart';
import 'package:meals/screens/categories.dart';
import 'package:meals/screens/meals.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;
var activePageTitle="Categories";
void _selectPage(int index){
setState((){
_selectedPageIndex=index;
});
}
@override
Widget build(BuildContext context){
Widget activePage=const CategoriesScreen();
if(_selectedPageIndex==1){
activePage=const MealsScreen( meals:[]);
activePageTitle="Your favorite";
}
'Front-End > Flutter_Project_03_ToDo APP' 카테고리의 다른 글
8.Udemy 강의를 통한 Meals Project (0) | 2025.01.27 |
---|---|
7.Udemy 강의를 통한 Meals Project (0) | 2025.01.21 |
6. Udemy 강의를 통한 Meals Project (0) | 2025.01.20 |