오늘은 주로 사용자 인터랙션과 관련된 컴포넌트들에 대해 알아보고자 한다.
무언가를 껐다 켤 때 사용하는 위젯으로, 우리에게 충분히 익숙한 위젯이다. 참고로 onChanged
부분이 null로 설정되있다면, 해당 스위치는 사용할 수 없는 disabled
상태가 된다.
class SwitchTest extends StatefulWidget {
const SwitchTest({Key? key}) : super(key: key);
State<SwitchTest> createState() => _SwitchTestState();
}
class _SwitchTestState extends State<SwitchTest> {
bool _switchValue = false; // 스위치의 상태를 위한 플래그 변수
// 스위치를 누를 때 실행될 함수
void _onChanged(bool value) {
setState(() {
_switchValue = value;
});
}
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Visibility( // Visibility 위젯을 이용하면 위젯을 보이거나 숨길 수 있음
visible: _switchValue,
maintainState: true,
maintainAnimation: true,
maintainSize: true,
child: Image.asset('images/icon1.png'), // 여기서는 이미지를 보이거나 숨김
),
Switch( 실제 스위치 위젯
value: _switchValue, 현재 스위치의 상태값
onChanged: (bool value) => _onChanged(value), // 스위치를 누르면 해당 값이 함수에 전달됨
),
Text(
'Switch value: $_switchValue',
style: const TextStyle(fontSize: 20),
),
const Text(
'스위치를 누르면 포챠펭이 나타납니다.',
style: TextStyle(fontSize: 20),
),
],
);
}
}
체크박스의 경우도 우리에게 익숙한 형태의 위젯이다. 스위와 마찬가지로 onChanged
가 null이면 체크박스를 클릭할 수 없다. 아래 예제는 다수의 체크박스가 있을 때 해당 체크박스를 클릭하면 옆에 있는 이미지가 표현된다.
class CheckboxTest extends StatefulWidget {
const CheckboxTest({Key? key}) : super(key: key);
State<CheckboxTest> createState() => _CheckboxTestState();
}
class _CheckboxTestState extends State<CheckboxTest> {
// 각 체크박스들의 상태를 저장하기 위한 변수
List<bool> checkboxValueList = [false, false, false];
// 각 이미지 파일들의 위치를 저장하는 변수
List<String> imageNameList = ['icon1.png', 'icon2.png', 'icon3.png'];
Widget build(BuildContext context) {
return ListView.separated( // 다수의 내용을 반복적으로 화면에 출력하기 위해 ListView를 사용했음
itemCount: checkboxValueList.length,
separatorBuilder: (context, index) => const Divider(
height: 5,
color: Colors.deepPurpleAccent,
),
itemBuilder: (BuildContext context, int index) { // 아이템 빌더로 화면에 반복적으로 표현될 데이터를 구성
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('포챠${index + 1}', style: const TextStyle(fontSize: 20)),
Checkbox( // 체크박스 위젯
value: checkboxValueList[index],
onChanged: (bool? value) { // 익명함수를 사용하여 바로 내역이 반영되도록 함
setState(() {
checkboxValueList[index] = value!;
});
},
),
Visibility( // Visibility 위젯을 사용
visible: checkboxValueList[index],
maintainState: true,
maintainAnimation: true,
maintainSize: true,
child: Image.asset(
'images/${imageNameList[index]}',
width: 200,
),
),
],
);
},
);
}
}
체크박스가 중복 가능하게 선택이 가능하다면, 라디오 버튼은 같은 카테고리 내에서 하나의 항목을 선택하기 위해 사용한다. 라디오 버튼은 일종의 그룹을 이루어야 하며 각 버튼은 groupValue
라고 하는 값으로 그룹을 지정할 수 있다.
class RadioTest extends StatefulWidget {
const RadioTest({Key? key}) : super(key: key);
State<RadioTest> createState() => _RadioTestState();
}
class _RadioTestState extends State<RadioTest> {
int _radioValue = 0; // 같은 그룹의 라디오 버튼이 공유하는 변수
List<String> imageNameList = ['icon1.png', 'icon2.png', 'icon3.png'];
void _handleRadioValueChange(int? value) {
setState(() {
_radioValue = value!;
});
}
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 3,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('포챠${index + 1}', style: const TextStyle(fontSize: 20)),
Radio(
value: index,
groupValue: _radioValue, // 이 값이 있어야 서로 같은 그룹의 라디오로 사용 가능
onChanged: (int? value) => _handleRadioValueChange(value),
),
Visibility(
visible: _radioValue == index, // 인덱스 비교를 통해 선택된 라디오 버튼만 이미지를 보여줌
maintainState: true,
maintainAnimation: true,
maintainSize: true,
child: Image.asset(
'images/${imageNameList[index]}',
width: 200,
),
),
],
);
},
);
}
}
범위 내에 있는 값을 선택할 때 유용하게 사용할 수 있는 슬라이더 위젯으로, 기본적으로 연속적인 값을 선택할 수 있으며, divisions
에 특정 정수를 지정하면 범위를 해당 갯수만큼 불연속적 선택이 가능하다.
class SliderTest extends StatefulWidget {
const SliderTest({Key? key}) : super(key: key);
State<SliderTest> createState() => _SliderTestState();
}
class _SliderTestState extends State<SliderTest> {
double _sliderValue = 0.0;
void _onChanged(double value) {
setState(() {
_sliderValue = value;
});
}
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 300,
child: Image.asset(
'images/icon1.png',
width: _sliderValue,
),
),
Slider(
value: _sliderValue,
min: 0.0,
max: 200.0,
// divisions: 10, // 10개의 구간으로 나누어서 표시, 없으면 연속적
label: '$_sliderValue',
onChanged: (double value) => _onChanged(value),
),
Text(
'Slider value: ${_sliderValue.toInt()}',
style: const TextStyle(fontSize: 20),
),
],
);
}
}
포챠펭이 너무 귀엽습니다ㅋㅋㅋㅋ 좋은 글 감사해요!!