플러터 커스텀 위젯(Custom Widget) 메모 입력 페이지 – 메모장 앱 만들기 (5)

안녕하세요. 지난 글에서는 리스트를 이용하여 데이터를 삽입, 삭제하는 방법에 대해서 설명드리고 상태 관리 기능을 이용하여 간단히 동작되는 메모 앱을 구현해보았습니다. 이번 글에서는 플러터 커스텀 위젯에 대해 알아보고 메모장을 보다 완성도 있게 만들기 위해 메모를 입력하기 위한 새로운 페이지를 만들어 보겠습니다.

플러터 강의 영상에서도 해당 글의 내용을 확인할 수 있습니다.

플러터 커스텀 위젯(Custom Widget)

커스텀 위젯(Custom Widget)은 개발자가 직접 만든 사용자 지정 위젯을 의미합니다. 플러터(flutter)에서 기본 제공 위젯을 조합하여 새로운 위젯을 만들거나, 기존 위젯을 확장하여 새로운 동작이나 스타일을 추가할 수 있습니다. 커스텀 위젯을 주로 다음과 같은 목적으로 사용됩니다.

  • 모듈화 및 재사용성 향상: 특정 화면이나 기능을 담당하는 위젯을 만들어 모듈화하면 코드의 가독성과 유지보수성이 향상되며, 재사용이 가능해집니다.
  • UI 스타일 통일성: 앱 내에서 일관된 디자인이나 스타일을 유지하기 위해 특정한 UI 요소들을 커스텀 위젯으로 만들어 사용할 수 있습니다.
  • 로직 분리: 특정 UI 요소와 관련된 비즈니스 로직을 커스텀 위젯 내에서 처리하여 코드를 더 간결하게 유지할 수 있습니다.

커스텀 위젯 사용방법

아래 코드들은 커스텀 위젯(Custom Widget)을 사용하기 위한 예시로 Container()을 여러 개 사용한다는 것 이외에는 이해할 필요는 없습니다.

children: [
  Container(
    margin: EdgeInsets.all(8.0),
    padding: EdgeInsets.all(16.0),
    decoration: BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.circular(8.0),
    ),
    child: Text(
      'Widget',
      style: TextStyle(
        fontSize: 18.0,
        color: Colors.white,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
  Container(
    margin: EdgeInsets.all(8.0),
    padding: EdgeInsets.all(16.0),
    decoration: BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.circular(8.0),
    ),
    child: Text(
      'Widget',
      style: TextStyle(
        fontSize: 18.0,
        color: Colors.white,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
  Container(
    margin: EdgeInsets.all(8.0),
    padding: EdgeInsets.all(16.0),
    decoration: BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.circular(8.0),
    ),
    child: Text(
      'Widget',
      style: TextStyle(
        fontSize: 18.0,
        color: Colors.white,
        fontWeight: FontWeight.bold,
      ),
    ),
  )
],

Container()을 커스텀 위젯으로 만들어 재활용할 수 있도록 합니다. 아래처럼 커스텀 위젯을 만들어줍니다. title, color 속성은 변수로 만들어 필수 인자로 받을 수 있게 합니다.

class CustomWidget extends StatelessWidget {

  final String title;  // 위젯의 제목을 저장하는 변수
  final Color color;   // 위젯의 배경색을 저장하는 변수

 // CustomWidget의 생성자. 제목과 배경색을 필수 인자로 받습니다.
  CustomWidget({required this.title, required this.color});

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(8.0),
      padding: EdgeInsets.all(16.0),
      decoration: BoxDecoration(
        color: color, // 커스텀 위젯의 호출시 파라미터 값을 가져옴
        borderRadius: BorderRadius.circular(8.0),
      ),
      child: Text(
        title, // 커스텀 위젯의 호출시 파라미터 값을 가져옴
        style: TextStyle(
          fontSize: 18.0,
          color: Colors.white,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

커스텀 위젯을 다음과 같이 재 활용할 수 있습니다. title, color 속성은 아규먼트(argument)으로 전달합니다.

children: [  
  // 커스텀 위젯 호출 및 파라미터값 전달
  CustomWidget(
    title: 'Widget 1',
    color: Colors.blue,
  ),
  CustomWidget(
    title: 'Widget 2',
    color: Colors.green,
  ),
  CustomWidget(
    title: 'Widget 3',
    color: Colors.orange,
  ),
],

메모장 입력 페이지 생성

메모장 앱에서 메모를 입력하기 위한 페이지를 생성합니다. home 속성에 MyMemoAppPage()를 주석 처리하고 새로운 위젯 MemoInputPage()을 만듭니다. 입력 페이지에서는 상태변화가 없기 때문에 StatelessWidget 을 사용합니다.

class MyMemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // home: MyMemoAppPage(),
      home: MemoInputPage(),
    );
  }
}

메인 페이지 위젯을 만든것 처럼 appBar, body 구조의 입력 페이지 화면의 위젯을 만들어줍니다, 새로운 위젯들은 아래 설명을 참고하시면 이해할 수 있습니다. 코드 구조와 아래 글 문단이 구조와 같으니 참고 부탁드립니다.

  • Padding: Padding 위젯은 내부의 자식 위젯에 여백을 추가하는 데 사용됩니다. 이것은 주로 디자인의 목적으로 사용되어 코드의 가독성을 높이고 요소들을 조절합니다.
    • Column: Column은 세로로 위젯들을 배열하는데 사용됩니다. 여기서는 세로로 텍스트 필드(TextField)와 버튼(ElevatedButton)을 배치합니다.
      • TextField: TextField는 사용자로부터 텍스트를 입력받을 수 있는 위젯입니다. 여기서는 controller 속성을 사용하여 텍스트 필드의 상태를 관리하는 컨트롤러 _textController를 연결했습니다.
      • SizedBox: SizedBox는 자식 위젯에 고정 크기의 여백을 추가하는 데 사용됩니다. 여기서는 텍스트 필드와 버튼 사이에 16.0의 높이를 가진 여백을 추가했습니다.
      • ElevatedButton: ElevatedButton은 사용자가 버튼을 누를 때 실행되는 함수를 지정하여 동작을 수행하는 버튼을 나타냅니다.
// MemoInputPage: 메모를 추가하는 페이지를 나타내는 Stateless 위젯
class MemoInputPage extends StatelessWidget {
  // 텍스트 필드의 상태를 관리하는 컨트롤러
  final TextEditingController _textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 페이지 상단의 앱 바 설정
      appBar: AppBar(
        title: Text('Add Memo'), // 앱 바 제목 설정
      ),
      // 페이지 본문 설정
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 텍스트를 입력받는 텍스트 필드 설정
            TextField(
              controller: _textController, // 컨트롤러 연결
              decoration: InputDecoration(labelText: 'Enter Memo'), // 힌트 텍스트 추가
            ),
            SizedBox(height: 16.0), // 텍스트 필드와 버튼 사이에 여백 추가
            // 메모를 추가하는 버튼 설정
            ElevatedButton(
              onPressed: () {},
              child: Text('Add Memo'), // 버튼에 표시될 텍스트
            ),
          ],
        ),
      ),
    );
  }
}

실행해보면 다음과 같은 입력페이지 위젯을 확인할 수 있습니다.

플러터-커스텀-위젯-메모장-입력-페이지

onPressed 속성에 _textController.text 값을 출력하도록 수정해봅니다.

ElevatedButton(
  onPressed: () {
    print(_textController.text);
  },
  child: Text('Add Memo'), // 버튼에 표시될 텍스트
),

앱에서 텍스트를 입력 후 버튼을 누르면 콘솔창에 표시되는 것을 확인할 수 있습니다. 이제 이 값을 메인 페이지에 넘겨서 화면을 업데이트해줘야 됩니다.

플러터-커스텀-위젯-메모장-입력-페이지-출력

마무리

지금까지 플러터에서 코드의 가독성과 유지 보수 재사용을 위한 커스텀 위젯 사용방법을 알아보고 보다 완성도 있는 메모장 앱을 만들기 위해 입력 페이지도 만들어 보았습니다. 다음 글에서는 메인 페이지에서 메모 입력페이지로 화면 전환을 하는 방법에 대해서 작성하겠습니다. 읽어주셔서 감사합니다.

전체 코드는 에서 확인할 수 있습니다.

Leave a Comment