들어가기 앞서...
Slider 를 사용하고, 상태값을 저장하고 다른 페이지에 상태값을 전달하는 방법을 배울것이다.
본문으로...
1. Slider 위젯 사용해보자!
1) 숫자랑, 버튼 UI 작업
children: [
Expanded(
child: Row(
children: 10000
.toString()
.split('')
.map((e) => Image.asset(
'asset/img/random_number/$e.png',
width: 50.0,
height: 70.0,
))
.toList(),
),
),
ElevatedButton(
onPressed: () {},
child: Text('저장!'),
style: ElevatedButton.styleFrom(backgroundColor: RED_COLOR),
)
],
2) 버튼 크기!
return Scaffold(
// 배경 색
backgroundColor: PRIMARY_COLOR,
// 하단바에 안붙게 적용
body: SafeArea(
// 패딩 (수평)가로 적용
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
// stretch 만 넣어도 버튼이 커지지만, SafeArea를 통해서 하단바에 안붙게 적용
crossAxisAlignment: CrossAxisAlignment.stretch,
3. Slider 위젯 추가
// # 필수로 있어야한다.
Slider(
value:,
onChanged: () {},
)
슬라이더가 변경 되고 , 위의 숫자도 변경이 된다.
double maxNumber= 10000;
...
Row(
children: maxNumber
.toInt()
...
)
...
Slider(
value: maxNumber,
min: 10000, // 최소
max: 1000000, // 최대
onChanged: (double val) {
setState(() { // 바로 상태 변경되게 setState
maxNumber = val;
});
},
),
2. 뒤로가기 버튼 기능!
매우 간단하다. 그리고 pop 을 하면서 파라미터를 넘겨주면된다.
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(maxNumber);
}
)
1) 파라미터를 받아보자
// _Header
IconButton(
// Navigator 로 해서 받을 예정이니깐 async await 로 해준다.
onPressed: () async {
// 변수로 선언을 해준다.
final result = await Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) {
return SettingScreen();
}));
// print 로 출력한다.
print(result);
},
)
State 클래스에서 선언한 maxNumber 변수에 Navigator 로 넘어온 파라미터값을 저장해주고 싶지만,
StatelessWidget 클래스에서 받아온 값을 State 클래스에 반영할 방법이 없다. 그렇기 때문에, onPressed 를 State 클래스에서 관리를 해주는 것이다.
{
_Header(onPressed: onSettingsPop),
...
void onSettingsPop() async {
final result = await Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) {
return SettingScreen();
}));
}
}
class _Header extends StatelessWidget {
final VoidCallback onPressed;
const _Header({required this.onPressed, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'랜덤함수 생성기',
style: TextStyle(
color: Colors.white, fontSize: 30.0, fontWeight: FontWeight.w700),
),
IconButton(
onPressed: onPressed,
icon: Icon(
Icons.settings,
color: RED_COLOR,
),
),
],
);
}
}
2) null 로 오는 경우를 체크 해줘야한다.
아이폰 같은 경우 옆에서 오른쪽으로 슬라이딩 하면 시스템적으로 뒤로가진다.
안드로이드 같은 경우도 뒤로 가기 버튼을 누르면 시스템적으로 뒤로 가진다.
그렇게 되면 우리가 값이 nullable 이기때문에(null 값으로 올수 있다.) 그래서 null 일때의 상황도 인지 해줘야한다.
// <int> 로 선언을 하면, 보내는 값의 타입을 int 로 설정할 수 있다.
// 하지만 이렇게 되면 setState 에러가 발생한다.
void onSettingsPop() async {
final int? result = await Navigator.of(context)
.push<int>(MaterialPageRoute(builder: (BuildContext context) {
return SettingScreen();
}));
if(result != null) {
setState(() {
maxNumber = result;
});
}
}
그리고 기존의 숫자를 1000으로 변경을 해주었다.
결과
3.세팅 스크린 초기값 변경!
위의 상황에서 다시 setting 숫자 페이지를 가게 된다면, 내가 maxNumber 설정한 42409 의 값이 있는게 아니고,
1000 으로 선언되어있는것을 볼 수 있다.
UI/UX 적으로 상태값을 초기로 돌리는 것보단 변경한 값을 가지고 있는것이 더 좋다.
해주고 싶은 작업은!
세팅 페이지에서 세팅 숫자를 정하고 난수를 생성한다음, 다시 세팅 페이지로 돌아갔을때, 정한 세팅 숫자를 기억하고 다시 넣어주면 되는것이다.
constructor 로 값을 던져주는 방법으로 진행읋 해볼것이다.
StatefulWidget 클래스도 파라미터 받아 변수에 저장을 해줄수 가있다.
// settings_screen.dart
// maxNumber 파라미터를 받아준다.
class SettingScreen extends StatefulWidget {
final int maxNumber;
const SettingScreen({required this.maxNumber, Key? key}) : super(key: key);
@override
State<SettingScreen> createState() => _SettingScreenState();
}
// random_number.dart
...
void onSettingsPop() async {
final result = await Navigator.of(context)
.push<int>(MaterialPageRoute(builder: (BuildContext context) {
// 넘겨줄때 매개 변수를 넘겨준다.
return SettingScreen(maxNumber: maxNumber,);
}));
}
이렇게 받은 파라미터를 StateClass 에 선언된 변수에 widget.maxNumber 로 변수에 할당 시켜주면 될것같지만, 그럴수가없다!!!
왜냐하면, State 클래스에 선언된 maxNumber 변수는 State 클래스가 생성 되기 전, StatefulWidget 이 만들지기전 미리 다 설정되어있기 떄문이다.
하지만 initState 가 있다.
initState 는 State 클래스가 (재)생성되는 순간! initState 가 실행이 된다. (StatefulWidget 의 값이 변경될때는 아니고!!!)
// State 클래스
class _SettingsScreenState extend State<SettingsScreen> {
double maxNumber = 1000;
// build 함수보다 먼저 initState 함수가 실행되어진다.
// 그러므로, maxNumber 에 값이 재할당 되어서 build 함수가 돌면서
// maxNumber 벼수는 재할당된 값으로 출력된다.
initState() {
super.initState();
maxNumber = widget.maxNumber.toDouble();
}
@override
Widget build() {
...
}
}
그러면 상태값이 유지가 되는 것을 볼 수 있다.
공통적으로 써진 코드 컴포넌트로 분리시켜보았다.
동일되는 코드를 컴포넌트로 빼서 import 해주도록 하자!
import 'package:flutter/material.dart';
class NumberRow extends StatelessWidget {
final int number;
const NumberRow({required this.number, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: number
.toInt()
.toString()
.split('')
.map((e) => Image.asset(
'asset/img/random_number/$e.png',
width: 50.0,
height: 70.0,
))
.toList(),
);
}
}
프로젝트가 커질수록 보기좋은 코드를 만들고, 정리를 잘해야한다.
끝으로...
- Silder 위젯을 사용하는 방법을 알았다.
- Navigator.pop()으로 파라미터를 보낼 수 있다.
- Navigator.pop 으로 받은 파라미터를 가지고 다시 State 클래스로 상태값을 보내서 유지하는 방법을 알았다.
- 코드를 보기 좋게 분리하는 방법을 배웠다.
