Flutter

[Flutter] 연습하기 4 - Flutter login app

연화 2025. 1. 13. 17:08

 

안녕하세요! 오늘은 Flutter를 활용하여 간단한 로그인 화면을 구현하는 방법을 공유하려 합니다.
이 프로젝트는 Flutter를 처음 배우는 분들도 쉽게 따라할 수 있도록 구성되어 있습니다.
기본적인 UI 구성부터 네비게이션까지 한 번에 익힐 수 있었습니다.

 

프로젝트 소개

Flutter를 사용하여 로그인 화면과 홈 화면을 구현합니다. 

  1. StatelessWidgetStatefulWidget의 사용법.
  2. TextFormField를 활용한 입력 폼 구성.
  3. Navigator를 사용한 화면 전환.
  4. Material Design을 활용한 UI 구성.

주요 기능

  1. 이메일 및 비밀번호 입력 폼.
  2. 입력 데이터의 유효성 검사 및 저장.
  3. 로그인 버튼 클릭 시 홈 화면으로 전환.

프로젝트 파일 구조

 

1. pubspec.yaml 설정

pubspec.yaml 파일은 프로젝트의 의존성과 자원을 관리합니다.
필요한 의존성을 추가하고, assets 폴더의 로고 이미지를 등록합니다.

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8
  flutter_svg: ^2.0.17

flutter:
  uses-material-design: true
  assets:
    - assets/logo.svg

 

2. 전역 상수 관리 (size.dart)

여백, 크기 등을 상수로 정의하여 프로젝트 전반에서 일관되게 사용할 수 있도록 합니다.

const double smallGap = 5.0;
const double mediumGap = 10.0;
const double largeGap = 20.0;
const double xlargeGap = 100.0;

 

3. 메인 진입점 (main.dart)

MaterialApp을 구성하고, 초기 화면(LoginPage)과 화면 전환(HomePage)을 설정합니다.

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        textButtonTheme: TextButtonThemeData(
          style: TextButton.styleFrom(
            backgroundColor: Colors.black,
            foregroundColor: Colors.white,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(30.0),
            ),
            minimumSize: Size(400, 60),
          ),
        ),
      ),
      initialRoute: '/login',
      routes: {
        '/login': (context) => LoginPage(),
        '/home': (context) => HomePage(),
      },
    );
  }
}

 

4. 컴포넌트 제작

(1) 텍스트 입력 필드 (custom_form_text_field.dart)

class CustomTextFormField extends StatelessWidget {
  final String label;
  final FormFieldSetter<String>? onSaved;

  const CustomTextFormField(this.label, this.onSaved);

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      decoration: InputDecoration(
        labelText: label,
        border: OutlineInputBorder(),
      ),
      validator: (value) {
        if (value == null || value.isEmpty) {
          return '${label}을 입력하세요';
        }
        return null;
      },
      onSaved: onSaved,
    );
  }
}

(2) 입력 폼 제작 (custom_form.dart)

class CustomForm extends StatelessWidget {
  final _formKey = GlobalKey<FormState>();
  String _email = '';
  String _password = '';

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          CustomTextFormField('Email', (value) {
            _email = value ?? '';
          }),
          SizedBox(height: mediumGap),
          CustomTextFormField('Password', (value) {
            _password = value ?? '';
          }),
          SizedBox(height: largeGap),
          TextButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                _formKey.currentState!.save();
                Navigator.pushNamed(context, '/home');
              }
            },
            child: Text('Login'),
          ),
        ],
      ),
    );
  }
}

 

5. 페이지 구성

(1) 로그인 페이지 (login_page.dart) 

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20.0),
        child: ListView(
          children: [
            SizedBox(height: xlargeGap),
            Logo('Login'),
            SizedBox(height: largeGap),
            CustomForm(),
          ],
        ),
      ),
    );
  }
}

(2) 홈 페이지 (home_page.dart) - 로그인 후 이동하게 될 화면

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Column(
          children: [
            SizedBox(height: xlargeGap),
            Logo('Care Soft'),
            SizedBox(height: largeGap),
            TextButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Get Started'),
            ),
          ],
        ),
      ),
    );
  }
}

 

완성 화면

 

 

이번 프로젝트를 통해 Flutter에서 로그인 화면을 구현하는 방법과 효율적인 컴포넌트 사용법을 배웠습니다.
이런 구조를 활용하면 앱 개발 속도를 높이고 유지보수성을 크게 향상시킬 수 있습니다.
다음에도 유용한 Flutter 실습 프로젝트로 찾아오겠습니다!

 

 

아래의 문헌을 참고하여 작성된 포스팅입니다.
최주호, 김근호, 이지원(공저) 『만들면서 배우는 플러터 앱 프로그래밍』, 앤써북, 2023.