[Flutter] Custom Radio Button 만들기

민태호·2025년 4월 30일
0

Flutter

목록 보기
18/23
post-thumbnail

일반적인 라디오 버튼이 아닌 아래와 같이 텍스트로 이루어진 라디오 버튼을 커스텀하고 싶었다.

비슷하게 성별을 선택할 수 있고, 비공개로 처리할 수도 있는 위젯을 만들어보겠다.
Provider를 이용하여 ViewViewModel로 나누어 구현하였다.

ViewModel

enum Gender { initialized, male, female, hide }
// enum으로 관리하는 예시
// 처음에 아무것도 선택되지 않은 상태를 위해 initialized 포함

class RadioViewModel extends ChangeNotifier {
	Gender gender = Gender.initialized; // 빈 초기값
	
    // 선택 성별 반영 함수 
	void changeGender(Gender genderValue) {
    	gender = genderValue;
    	notifyListeners();
	}
}

Viewmodel은 선택된 데이터와 선택사항을 반영하는 함수로만 이루어져있기 때문에 간단하다.

View


class RadioView extends StatelessWidget {
  const RadioView({super.key});

  final MaterialColor maleColor = Colors.blue;
  final MaterialColor femaleColor = Colors.pink;

  
  Widget build(BuildContext context) {
    final RadioViewModel viewmodel = Provider.of<RadioViewModel>(context);

    return Scaffold(
      appBar: AppBar(title: Text("Custom Radio Demo")),
      body: Center(
        child: SizedBox(
          height: 200,
          width: 160,
          child: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text("성별"),
                  Row(
                    children: [
                      Checkbox(
                        // 비공개 상태에서만 활성화되므로, 성별을 선택했을 때에는 해제된다.
                        value: viewmodel.gender == Gender.hide,
                        onChanged: (value) {
                          if (value!) {
                            viewmodel.changeGender(Gender.hide);
                          }
                        },
                      ),
                      Text("비공개"),
                    ],
                  ),
                ],
              ),
              Row(
                spacing: 10,
                children: [
               	  // 쉬운 구현을 위해 OutlinedButton을 사용함
                  // 선택된 성별에 따라서 스타일 적용
                  // 선택 상태를 적용하는 조건과 활성화 색상을 지정하는 Custom 함수 적용
                  Expanded(
                    child: OutlinedButton(
                      onPressed: () => viewmodel.changeGender(Gender.male),
                      style: customRadioButtonStyle(
                        isSelected: viewmodel.gender == Gender.male,
                        mainColor: maleColor,
                      ),
                      child: Icon(
                        Icons.male,
                        size: 30,
                        color:
                            viewmodel.gender == Gender.male
                                ? maleColor.shade400
                                : Colors.black45,
                      ),
                    ),
                  ),
                  Expanded(
                    child: OutlinedButton(
                      onPressed: () => viewmodel.changeGender(Gender.female),
                      style: customRadioButtonStyle(
                        isSelected: viewmodel.gender == Gender.female,
                        mainColor: femaleColor,
                      ),
                      child: Icon(
                        Icons.female,
                        size: 30,
                        color:
                            viewmodel.gender == Gender.female
                                ? femaleColor.shade400
                                : Colors.black45,
                      ),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

아래는 위 View에서 사용한 함수이며, 활성화 조건 isSelected와 메인 색상 mainColor를 받아서 그에 맞게 스타일을 반환해준다.


ButtonStyle customRadioButtonStyle({
  required bool isSelected,
  required MaterialColor mainColor,
}) {
  return ButtonStyle(
    side: WidgetStatePropertyAll(
      BorderSide(
        color: isSelected ? mainColor.shade300 : Colors.black45,
        width: 2,
      ),
    ),
    backgroundColor: WidgetStatePropertyAll(
      isSelected ? mainColor.shade50 : Colors.transparent,
    ),
  );
}

ProviderMVVM구조를 사용하지 않고 StatefulWidget으로만 구현한다면, 위 ViewModel에서 관리했던 상태 변수들을 위젯 내부에 선언하고, notifyListeners대신 setState함수를 이용하면 된다.

실행 화면

profile
Flutter Developer

0개의 댓글