Flutter 일기 56번째
참고 : https://api.flutter.dev/flutter/material/Slider-class.html
https://api.flutter.dev/flutter/material/RangeSlider-class.html
특정 범위 내에서 값을 선택할 때 사용하는 위젯으로, 굉장히 자주 사용된다. 기본적인 형태는 아래와 같이 생겼다.
const Slider({
super.key,
required this.value,
required this.onChanged,
this.onChangeStart,
this.onChangeEnd,
this.min = 0.0,
this.max = 1.0,
this.divisions,
this.label,
this.activeColor,
this.inactiveColor,
this.thumbColor,
this.mouseCursor,
this.semanticFormatterCallback,
this.focusNode,
this.autofocus = false,
})
생성자는 이렇게 생겼는데 value, onChanged property는 꼭 넣어줘야한다.
Slider위젯의 상태가 변경될때마다 onChanged property에 설정된 함수를 호출하고, 변경된 value에 맞게 위젯을 다시 빌드하게 된다. 그래서 애초에 Slider위젯은 StatefulWidget을 상속받는 형태이다.
flutter.dev에서 가장 간단한 예시를 가져다가 실행해보았다.
class SliderExample extends StatefulWidget {
const SliderExample({super.key});
State<SliderExample> createState() => _SliderExampleState();
}
class _SliderExampleState extends State<SliderExample> {
double _currentSliderValue = 20;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Slider')),
body: Slider(
value: _currentSliderValue,
max: 50,
label: _currentSliderValue.toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
print(_currentSliderValue);
});
},
),
);
}
}
onChanged에 설정한 setState 함수 내부에서, _currentSliderValue를 계속 변경해주고 있는 것을 알 수 있다.
min 기본값이 0이기 때문에, min 값을 위젯에 따로 설정해주지 않아도 0으로 되어있다.
label 이라는 property도 있는데 화면에서는 나타나지 않았다. 왜일까?
아래의 두 줄을 Slider위젯 안에 넣어보자.
divisions: 5,
label: _currentSliderValue.round().toString(),
divisions 인자를 넣어서 구간을 나눠주면 잘 나타나는 것을 알 수 있는데, SliderThemeData 설정에 가보면
return SliderThemeData(
...
showValueIndicator: ShowValueIndicator.onlyForDiscrete,
);
Discrete, 불연속적인 값에 대해서만 valueIndicator가 나타나도록 설정되어 있다. ShowValueIndicator.always 또는 ShowValueIndicator.onlyForContinuous로 바꿔주면 연속적인 범위 내에서도 잘 동작한다.
body: SliderTheme(
data: const SliderThemeData(showValueIndicator: ShowValueIndicator.always),
child: Slider(
value: _currentSliderValue,
max: 50,
// divisions: 5,
label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
),
Slider위젯의 property를 다시 살펴보면, 이런 걸 갖고 있다.
Slider(
activeColor: Colors.blue,
inactiveColor: Colors.green,
thumbColor: Colors.red,
)
저 동그라미인 thumb를 뭐라고 해석해야 되나...? 아무튼 저렇게 색상을 바꿀 수 있는데, Slider위젯 내부에서 설정하려면 속성이 한정적이다. Slider위젯을 좀 더 예쁘게 꾸미려면, SliderThemeData 라는 것이 필요하다. ThemeData.sliderTheme에서 설정하거나, SliderTheme위젯으로 Slider위젯 전체를 감싸주면 된다.
return MaterialApp(
theme: ThemeData(
sliderTheme: SliderThemeData(inactiveTrackColor: Colors.green), ...),
home: const SliderExample(),
);
이렇게 MaterialApp에서 설정해줘도 되는데, 나는 Slider위젯을 감싸는 형태로 적어보겠다. 어차피 SliderThemeData를 쓴다는 점은 똑같다.
body: SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Color(0xFF4CAF50),
inactiveTrackColor: Color(0xFF757575),
thumbColor: Color(0xFFCDDC39),
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 20.0),
//
overlayColor: Color(0xFFCDDC39).withOpacity(0.2),
overlayShape: RoundSliderOverlayShape(overlayRadius: 40.0),
showValueIndicator: ShowValueIndicator.onlyForContinuous,
valueIndicatorShape: PaddleSliderValueIndicatorShape(),
// valueIndicatorShape 의 기본값은 RectangularSliderValueIndicatorShape 인 듯
),
child: Slider(
... 이전 코드와 같음
),
copyWith 메소드는 객체가 원래 갖는 속성들, 그러니까 필드 설정값을 그대로 복사해다가 일부만 새로운 값으로 변경할 때 쓴다. 사실 저기서
1. 이렇게 쓰던지
data: SliderTheme.of(context).copyWith(
2. 아님 이렇게 쓰던지
data: SliderThemeData(
실행화면 상으로는 차이가 없더라. 하지만 copyWith 이걸 많이들 사용하는 것 같다.
overlay는 위처럼 thumb 주변으로 나타나는 좀 더 큰 원 부분이다. showValueIndicator는 위에서 division과 함께 설명했고, PaddleSliderValueIndicatorShape를 적용했더니 저렇게 원 모양으로 나타났다. 설정 안하면 네모 모양이다.
Slider위젯은 사실상 값이 1개인 Slider인데, 아래 그림처럼 1개 값이 아닌 범위 값을 선택하는 Slider를 원한다면 RangeSlider를 쓰면 된다.