간단하게 쇼핑앱의 화면을 이용해서 상태변경을 연습해보자
StatefulWidget으로 만든뒤에 상태필드를 추가한다.
class ShoppingCartHeader extends StatefulWidget {
State<ShoppingCartHeader> createState() => _ShoppingCartHeaderState();
}
class _ShoppingCartHeaderState extends State<ShoppingCartHeader> {
int selectedId = 0;
// 생략
먼저 사진을 변경해보자
그림을 넣고
List<String> selectedPic = [
"assets/p1.jpeg",
"assets/p2.jpeg",
"assets/p3.jpeg",
"assets/p4.jpeg",
];
Widget _buildHeaderPic() {
return Padding(
padding: const EdgeInsets.all(16.0),
child: AspectRatio(
aspectRatio: 5/3,
child: Image.asset(
selectedPic[selectedId], // 리스트 인덱스
fit: BoxFit.cover,
),
),
);
}
버튼을 만들고
Widget _buildHeaderSelector(){
return Padding(
padding: const EdgeInsets.only(left: 30, right: 30, top: 10, bottom: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildHeaderSelectorButton(0, Icons.directions_bike),
_buildHeaderSelectorButton(1, Icons.motorcycle),
_buildHeaderSelectorButton(2, CupertinoIcons.car_detailed),
_buildHeaderSelectorButton(3, CupertinoIcons.airplane),
],
),
);
}
버튼이 선택되었을때만 색깔이 들어오게 만들고 상태값 변경
Widget _buildHeaderSelectorButton(int id, IconData mIcon) {
return Container(
width: 70,
height: 70,
decoration: BoxDecoration(
color: id == selectedId ? kAccentColor : kSecondaryColor,
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
icon: Icon(mIcon, color: Colors.black),
onPressed: () {
setState(() {
selectedId = id;
});
},
),
);
}
이제 버튼을 클릭하게 되면 해당 버튼에 따라 사진이 바뀌게 된다.
하단 부분을 다른 위젯으로 만든다.
칼라 옵션을 스택으로 만들었다.
Widget _buildDetailIcon(Color mColor) {
return Padding(
padding: EdgeInsets.only(right: 10),
child: Stack(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration( // 데코레이션으로 모양주는 방법
color: Colors.white,
border: Border.all(), // 모든 방향으로
shape: BoxShape.circle), // 보더를 둥글게
),
Positioned(
left: 5,
top: 5,
child: ClipOval( // 원모양으로 자르는 방법
child: Container(
color: mColor,
width: 40,
height: 40,
),
),
),
],
),
);
}
화면의 버튼을 클릭했을때 다른위젯의 텍스트 문구의 숫자도 바뀌게 하려고 한다.
먼저 바꿀위젯과 버튼위젯을 모두 가지는 상위위젯을 StatefulWidget
으로 바꾼다.
상태를 공유할수 있도록 추가한다. -> _test
그리고 상태를 변경하는 메소드를 하나 만든다. -> updateState
class ShoppingCartPage extends StatefulWidget {
State<ShoppingCartPage> createState() => _ShoppingCartPageState();
}
class _ShoppingCartPageState extends State<ShoppingCartPage> {
int _test = 0;
void updateState(int id){
setState(() {
_test = id;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildShoppingCartAppBar(),
body: Column(
children: [
ShoppingCartHeader(updateState: updateState,), // 첫번째 클래스(이미지변경, 버튼)
ShoppingCartDetail(id: _test), // 다른 클래스(문구변경)
],
),
);
}
}
버튼을 클릭했을때 상태를 공유하기 위해 상위위젯의 상태를 변경하는 메소드를 매개변수로 전달한다.
class ShoppingCartHeader extends StatefulWidget {
const ShoppingCartHeader({Key? key, required this.updateState}) : super(key: key);
final Function(int) updateState; // 메소드 주입
// 생략
버튼 클릭시 가져온 메소드를 호출한다.
onPressed: () {
setState(() {
selectedId = id;
widget.updateState(id); // 추가한 코드
});
},
상태를 전달하기 위해 매개변수를 추가한다.
class ShoppingCartDetail extends StatelessWidget {
const ShoppingCartDetail({Key? key, required this.id}) : super(key: key);
final int id;
// 생략
바꾸고 싶은 문구를 $
로 추가한다.
Text(
"Urban Soft AL 10.0 $id",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
이제 버튼을 클릭하게 되면 상위위젯의 업데이트메소드를 호출하고 상위위젯의 상태를 변경하게된다.
상위위젯을 상태를 다른 위젯이 공유하므로 다른위젯도 다시 렌더링이 된다.
이런 방법은 위젯트리에서 가까운 위젯이라서 사용하는 방법이지 위젯끼리의 거리가 멀다면 필요없는 렌더링을 할수도 있다.
다음에는 외부에 상태를 저장해서 변경되는 부분만 다시 렌더링 하는 방법을 알아보자.