StatefulWidget
StatefulWidget은 Flutter에서 상태를 가지는 위젯을 정의하는 데 사용됩니다. 상태(State)는 시간이 지남에 따라 변경될 수 있는 데이터를 의미하며, 이 상태의 변화에 따라 UI를 다시 렌더링할 수 있습니다.
StatefulWidget은 두 가지 주요 클래스를 조합하여 작동합니다:
- StatefulWidget 클래스:
- 변경되지 않는 부분(위젯 자체)을 정의.
- 상태를 관리할 State 객체를 생성.
- createState() 메서드를 통해 상태 객체를 반환.
- State 클래스:
- 상태를 보유.
- build() 메서드를 사용해 UI를 생성.
- 상태가 변경되면 setState()를 호출하여 화면을 다시 그림.
StatefulWidget vs StatelessWidget
특징 | StatefulWidget | StatelessWidget |
상태 관리 | 상태를 가질 수 있음 | 상태를 가지지 않음 |
UI 갱신 가능 여부 | setState()를 통해 UI 갱신 가능 | 상태 변경 불가능, 고정된 UI를 가짐 |
사용 예시 | 폼 입력, 카운터 앱, 애니메이션 등 | 텍스트, 아이콘, 버튼 등의 고정된 UI |
라이프사이클 | initState(), dispose() 등 관리 가능 | 별도의 라이프사이클 없음 |
+) 콜백은 특정 작업이 완료되거나 특정 이벤트가 발생했을 때 호출되는 함수를 말합니다. 간단히 말해, "나중에 호출되는 함수"입니다.
위젯 트리 구조
- HomeScreen (StatefulWidget)
- 공유 상태: 대출 목록 (장바구니 역할).
- 화면 전환을 위한 BottomNavigationBar를 포함.
- Library (도서 목록)
- BookListPage에서 도서 선택/해제를 처리.
- BorrowList (장바구니)
- BookCartPage로 구현. (Placeholder로 대체).
homePage (StatefulWidget)
| ├── 공유 상태: 대출 목록에 추가된 도서 목록 (공유 상태)
|
├── Library (Store 역할)
| ├── Book 1 (도서 목록)
| ├── Book 2
| ├── Book 3
| └── Book 4
|
└── BorrowList (Cart 역할)
├── Book 2 (대출 목록에 추가된 책)
└── Book 4
주요 상태 및 메서드
공유 상태: mySelectedBook
- 선택된 도서 리스트를 관리.
- setState()로 상태 변경 시 UI를 갱신.
상태 변경 메서드: _toggleSaveStates(String book)
- 도서가 선택된 상태면 리스트에서 제거.
- 선택되지 않은 상태면 리스트에 추가.
주요 파일별 설명
main2.dart
앱의 진입점이며 MaterialApp을 생성합니다.
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
home: HomeScreen(),
),
);
}
HomeScreen
- 상태 관리 및 BottomNavigationBar를 통한 화면 전환 처리.
BookListPage
- 도서 목록 표시 및 선택 상태를 아이콘으로 보여줌.
- 부모 위젯에서 전달받은 onToggleSaved 콜백으로 상태 변경.
BookCartPage
- 선택된 도서를 장바구니에서 확인할 화면 (현재는 Placeholder 사용).
전체 코드 구조
// main2.dart
import 'package:flutter/material.dart';
import 'home_screen.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
home: HomeScreen(),
));
}
// home_screen.dart
import 'package:flutter/material.dart';
import 'book_list_page.dart';
import 'book_cart_page.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int pageIndex = 0;
List<String> mySelectedBook = [];
void _toggleSaveStates(String book) {
setState(() {
if (mySelectedBook.contains(book)) {
mySelectedBook.remove(book);
} else {
mySelectedBook.add(book);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('텐코에 서재'),
backgroundColor: Theme.of(context).colorScheme.tertiaryContainer,
),
body: IndexedStack(
index: pageIndex,
children: [
BookListPage(
onToggleSaved: _toggleSaveStates,
selectedBook: mySelectedBook,
),
BookCartPage(),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: pageIndex,
onTap: (index) {
setState(() {
pageIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.list),
label: 'book-list',
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
label: 'cart',
),
],
),
);
}
}
// book_list_page.dart
import 'package:flutter/material.dart';
class BookListPage extends StatelessWidget {
final Function(String) onToggleSaved;
final List<String> selectedBook;
const BookListPage({
required this.onToggleSaved,
required this.selectedBook,
super.key,
});
final List<String> books = [
'호모사피엔스',
'다트입문',
'홍길동전',
'코드리팩토링',
'전치사도감',
];
@override
Widget build(BuildContext context) {
return ListView(
children: books.map((book) {
final isSelectedBook = selectedBook.contains(book);
return ListTile(
leading: Container(
width: 35,
height: 35,
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor,
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: Colors.black),
),
),
title: Text(
book,
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
trailing: IconButton(
onPressed: () {
onToggleSaved(book);
},
icon: Icon(
isSelectedBook ? Icons.remove_circle : Icons.add_circle,
color: isSelectedBook ? Colors.red : Colors.green,
),
),
);
}).toList(),
);
}
}
// book_cart_page.dart
import 'package:flutter/material.dart';
class BookCartPage extends StatelessWidget {
const BookCartPage({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}