ToggleButtons class
토글 버튼 세트.
자식 목록은 direction 을 따라 배치됩니다. 각 버튼의 상태는 isSelected 에 의해 제어되는데, isSelected 는 버튼이 선택되었는지 선택되지 않았는지 여부를 판별하는 부울 값 목록입니다. 두 값 모두 목록의 인덱스를 기준으로 연관됩니다. isSelected 의 길이는 자식 목록의 길이와 일치해야 합니다.
이 구성 요소에는 Material 3 버전인 SegmentedButton 이 있는데 , 이는 Material 3에 대해 구성된 애플리케이션에 더 적합합니다(ThemeData.useMaterial3 참조)
공식 문서 코드
앱을 구성할 때 빠질 수 없는 요소 중에 뭐가 있을까? 나는 그것들 중 하나가 바로 버튼이라고 생각한다. 스위치가 되었든 라디오 버튼이 되었든 일단 클릭할 수 있고 그로 인해서 상태가 변하는 버튼 말이다. 근데 그러한 버튼을 하나 두 개는 괜찮지만 여러 개의 버튼 중 다수 혹은 단일 버튼을 선택하게 하려면 조금 귀찮게 된다.
여기서 이러한 작업을 간단하게 만들어주는 위젯이 있는데 바로 ToggleButtons 위젯이다.
이 ToggleButtons 위젯은 여러 개의 버튼 중 다수 혹은 단일 버튼을 선택할 수 있게 해주는 위젯이다. 주로 bool 값의 리스트로 각각의 버튼이 선택되어 있는지의 대한 상태를 관리하고 다양한 상태 기반 UI 구성에 유용하게 사용된다. 바로 알아보자.
하위 속성
| 속성명 | 타입 | 기본값 | 설명 |
| children | List<Widget> | – | 버튼으로 표시될 위젯 목록 |
| isSelected | List<bool> | – | 각 버튼의 선택 여부를 나타내는 리스트 |
| onPressed | void Function(int)? | null | 버튼이 눌렸을 때 실행될 콜백 함수 |
| mouseCursor | MouseCursor? | null | 마우스 커서 스타일 |
| tapTargetSize | MaterialTapTargetSize? | ThemeData.materialTapTargetSize | 터치 영역 최소 크기 설정 |
| textStyle | TextStyle? | null | 버튼 내부 텍스트 스타일 |
| constraints | BoxConstraints? | null | 버튼의 크기 제약 조건 |
| color | Color? | null | 선택되지 않은 활성 버튼의 텍스트 및 아이콘 색상 |
| selectedColor | Color? | null | 선택된 버튼의 텍스트 및 아이콘 색상 |
| disabledColor | Color? | null | 비활성화된 버튼의 텍스트 및 아이콘 색상 |
| fillColor | Color? | null | 선택된 버튼의 배경색 |
| focusColor | Color? | null | 포커스된 버튼의 배경색 |
| highlightColor | Color? | null | 하이라이트 색상 (터치 시 효과) |
| hoverColor | Color? | null | 마우스 호버 시 색상 |
| splashColor | Color? | null | 버튼 눌렀을 때 잉크 효과 색상 |
| focusNodes | List<FocusNode>? | null | 각 버튼에 대한 포커스 노드 리스트 |
| renderBorder | bool | true | 버튼 테두리 표시 여부 |
| borderColor | Color? | null | 테두리 색상 (비선택 상태) |
| selectedBorderColor | Color? | null | 테두리 색상 (선택 상태) |
| disabledBorderColor | Color? | null | 테두리 색상 (비활성 상태) |
| borderRadius | BorderRadius? | null | 버튼 테두리의 모서리 반경 |
| borderWidth | double? | 1.0 | 버튼 테두리의 두께 |
| direction | Axis | Axis.horizontal | 버튼을 배치할 방향 |
| verticalDirection | VerticalDirection | VerticalDirection.down | 수직 방향일 때 버튼 배치 순서 |
이 위젯을 처음 본다면 그냥 일반적인 버튼을 하나 만들어주는 위젯이라고 생각할 수 있다. 하지만 이 위젯은 그러한 범/부 같은 위젯이 아닌 한 번에 여러 개의 상태를 관리하고 만들어줄 수 있는 위젯이다.
ToggleButtons(
children: [
Icon(Icons.local_cafe),
Icon(Icons.fastfood),
Icon(Icons.cake),
],
)
일단 먼저 ToggleButtons 를 사용하려면 children 에 다양한 버튼에 사용할 위젯을 목록에 추가해줘야 한다.
위처럼 선언했으면 이제 버튼을 3개 만들겠다고 해준 거고 그 3개의 버튼에 들어갈 아이콘을 넣어준 것이 되는 것이다.
그다음은 selected 파라미터를 설정해줘야 한다.
List<bool> isSelected = [true, false, false];
ToggleButtons(
isSelected: isSelected,
children: [
Icon(Icons.local_cafe),
Icon(Icons.fastfood),
Icon(Icons.cake),
],
)
isSelected 는 List<bool> 타입을 갖고 있는데 여기서 리스트의 인덱는 각 버튼과 매칭되게 된다.
이 isSelected 는 어떤 버튼을 선택하고 있는지의 대한 상태 관리를 해주기 때문에 굉장히 중요하다.
그리고 마지막으로 버튼을 눌렀을 때의 반응을 위하여 onPressed 파라미터를 사용하여 함수를 전달해 준다.
void onPressed(int index) {
setState(() {
for (int i = 0; i < isSelected.length; i++) {
isSelected[i] = i == index;
}
});
}
ToggleButtons(
onPressed: (index) => onPressed(index),
isSelected: isSelected,
children: [
Icon(Icons.local_cafe),
Icon(Icons.fastfood),
Icon(Icons.cake),
],
),
위에서 처럼 for 문 안에 isSelected[i] = i == index 으로 만들어주면 단일 선택 동작을 구현 할 수 있게 된다.
이렇게 간단한 코드만으로 단일 선택 동작을 하는 버튼을 만들 수 있게 되었다.
근데 단일 선택이 아니라 다중 선택으로 구현하고 싶다면 isSelected[index] = !isSelected[index] 로 만들어주면 간단하게 된다.

근데 여기서 이제 생긴 게 마음에 안들 수 있다. 그러니 하위 속성을 통해 간단하게 디자인을 해보자.
먼저 color 와 selectedColor 로 선택되지 않은 버튼의 아이콘 색상과 선택된 버튼의 아이콘 색상을 바꿔줄 수 있다.
color: Colors.red,
selectedColor: Colors.blue,

그리고 이 배경 색은 fillColor 라는 속성으로 지정해 줄 수 있다.
fillColor: Colors.greenAccent,

또한 이 버튼의 경계, 보더도 renderBorder 값을 false 로 지정함으로써 없앨 수 있다.(난 개인적으로 이게 젤 예쁜 것 같다.)
renderBorder: false,

아니면 아예 이렇게 래디우스를 줘서 SegmentedButton 처럼 꾸며버릴 수도 있다.
borderRadius: BorderRadius.all(Radius.circular(30)),

그 밖에서 하이라이트 색상과 InWell 에 맞는 색상을 선택할 수도 있고 PC 버전에서라면 호버기능과 포커스기능도 지원해주고 있다.
이렇게 ToggledButtons 에 대해서 알아보았는데 실질적인 난이도는 엄청나게 쉬운데 반해 예제코드를 해괴망측하게 만들어놔서 처음 접했을 때 바로 튀어버린 기억이 있다. 암튼 도움이 되었길 바라며 마치겠다.