Flutter : 재사용 가능한 위젯 만들기

koeyhoyh·2022년 7월 9일
1

App_Flutter

목록 보기
12/19

참고:
https://medium.com/flutter-community/flutter-reusable-widgets-38e270846d59
https://github.com/aanalmehta/flutter_reusable_widgets/blob/master/lib/text_form_widget.dart


우리는 위젯을 조금만 바꾸어 사용하는 일이 잦습니다. 텍스트만 바꾼 동일한 디자인의 텍스트박스, 여러 버튼 등이 그 예입니다.

단 한번만 사용할 위젯을 만드는 것이 아니라면, 재사용 가능한 위젯을 만드는 것이 훨씬 더 편리하고, 관리하기 쉽습니다.

만드는 방법은 쉬운데, 크게 2가지 방법이 있습니다.

자주 사용할 위젯의 class를 만들어주는 방법,
위젯에서 수정할 부분만 빼고 원형을 미리 만들어 놓는 방법입니다.

class를 이용한 방법의 예제

class TextFormFieldWidget extends StatefulWidget {
  final TextInputType textInputType;
  final String hintText;
  final Widget prefixIcon;
  final String defaultText;
  final FocusNode focusNode;
  final bool obscureText;
  final TextEditingController controller;
  final Function functionValidate;
  final String parametersValidate;
  final TextInputAction actionKeyboard;
  final Function onSubmitField;
  final Function onFieldTap;

  const TextFormFieldWidget(
      { this.hintText,
      this.focusNode,
      this.textInputType,
      this.defaultText,
      this.obscureText = false,
      this.controller,
      this.functionValidate,
      this.parametersValidate,
      this.actionKeyboard = TextInputAction.next,
      this.onSubmitField,
      this.onFieldTap,
      this.prefixIcon});

  
  _TextFormFieldWidgetState createState() => _TextFormFieldWidgetState();
}

class _TextFormFieldWidgetState extends State<TextFormFieldWidget> {
  double bottomPaddingToError = 12;

  
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        primaryColor: primaryColor,
      ),
      child: TextFormField(
        cursorColor: primaryColor,
        obscureText: widget.obscureText,
        keyboardType: widget.textInputType,
        textInputAction: widget.actionKeyboard,
        focusNode: widget.focusNode,
        style: TextStyle(
          color: colorBlack,
          fontSize: 16.0,
          fontWeight: FontWeight.w200,
          fontStyle: FontStyle.normal,
          letterSpacing: 1.2,
        ),
        initialValue: widget.defaultText,
        decoration: InputDecoration(
          prefixIcon: widget.prefixIcon,
          hintText: widget.hintText,
          enabledBorder: OutlineInputBorder(
            borderSide: BorderSide(color: primaryColor),
          ),
          focusedBorder: OutlineInputBorder(
            borderSide: BorderSide(color: primaryColor),
          ),
          hintStyle: TextStyle(
            color: Colors.grey,
            fontSize: 14.0,
            fontWeight: FontWeight.w300,
            fontStyle: FontStyle.normal,
            letterSpacing: 1.2,
          ),
          contentPadding: EdgeInsets.only(
              top: 12, bottom: bottomPaddingToError, left: 8.0, right: 8.0),
          isDense: true,
          errorStyle: TextStyle(
            color: colorRed,
            fontSize: 12.0,
            fontWeight: FontWeight.w300,
            fontStyle: FontStyle.normal,
            letterSpacing: 1.2,
          ),
          errorBorder: OutlineInputBorder(
            borderSide: BorderSide(color: primaryColor),
          ),
          focusedErrorBorder: OutlineInputBorder(
            borderSide: BorderSide(color: primaryColor),
          ),
        ),
        controller: widget.controller,
        validator: (value) {
          if (widget.functionValidate != null) {
            String resultValidate =
                widget.functionValidate(value, widget.parametersValidate);
            if (resultValidate != null) {
              return resultValidate;
            }
          }
          return null;
        },
        onFieldSubmitted: (value) {
          if (widget.onSubmitField != null) widget.onSubmitField();
        },
        onTap: () {
          if (widget.onFieldTap != null) widget.onFieldTap();
        },
      ),
    );
  }
}

해당 class는 밑의 코드처럼 사용합니다.

Widget _buildPassword() {
    return TextFormFieldWidget(
      hintText: "Password",
      obscureText: true,
      textInputType: TextInputType.visiblePassword,
      actionKeyboard: TextInputAction.done,
      functionValidate: commonValidation,
      controller: _passwordController,
      focusNode: _passwordControllerFocus,
      onSubmitField: () {},
      parametersValidate: "Please enter password.",
      prefixIcon: Icon(Icons.keyboard_hide),
    );
  }

코드가 길어 보이지만, 핵심은
조금씩 바꿀 속성들은 widget.XXXX로 실제 사용할 곳에서 지정해주고, 나머지는 다른 속성들을 미리 만들어놓습니다.


다음 방법입니다. 수정할 부분만 제거한, 함수 원형을 만들어 놓는 방법입니다.

위젯 원형을 만들어 놓는 방법 예제

import 'package:flutter/material.dart';

Container customToggleBtnWidget({
  required List<bool> isSelected,
  required Function(int) onClick,
}) {
  return Container(
    margin: const EdgeInsets.all(30),
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(5),
    ),
    child: ToggleButtons(
      isSelected: isSelected,
      onPressed: (int index) {
        return onClick(index);
      },
      color: Colors.grey,
      disabledColor: Colors.white,
      renderBorder: false,
      borderWidth: 0,
      borderColor: Colors.white,
      selectedColor: Colors.black,
      borderRadius: BorderRadius.circular(10),
      fillColor: Colors.white,
      selectedBorderColor: Colors.white,
      children: const [
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 35),
          child: Text(
            '기록',
            style: TextStyle(
              fontSize: 24,
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 35),
          child: Text(
            '조회',
            style: TextStyle(
              fontSize: 24,
            ),
          ),
        ),
      ],
    ),
  );
}

onclick 과 isSelected 를 다르게 사용할 것입니다.
class와 달라진 것은 한 가지입니다. 다르게 사용할 속성에 required를 적어놓고, 위젯을 만들 때는 required를 채워준 후 사용합니다.

  Widget customToggleBtn2() {
    return (customToggleBtnWidget(
      onClick: (index) {
        setState(() {
          isSelected[index] = !isSelected[index];
        });
        if (isSelected[0]) {
          Navigator.popAndPushNamed(context, '/');
          isSelected[1] = false;
        } else if (isSelected[1] && flag != 2) {
          Navigator.popAndPushNamed(context, '/first');
          isSelected[0] = false;
        }
      },
      isSelected: isSelected,
    ));
  }

이것으로 위젯을 재사용하는 방법에 대해 알아보았습니다.
모르시는 분들께 도움이 많이 되었으면 좋겠습니다.
설명 마치겠습니다. 감사합니다 : )

profile
내가 만들어낸 것들로 세계에 많은 가치를 창출해내고 싶어요.

0개의 댓글