미새문지

24.10.31 flutter navigator 본문

개발 TIL

24.10.31 flutter navigator

문미새 2024. 10. 31. 18:40
728x90

몇몇 앱들을 보면 들어가자마자 로그인부터 해야 작동하는 앱들이 있다. 보통은 로그인을 안해도 어플을 켤 수 있지만 개인정보가 필요한 앱의 경우 로그인을 통해 데이터를 넘겨줘야 하기 때문이다.

그래서 초기 페이지를 로그인으로 잡아보려고 한다.

import 'package:flutter/material.dart';
import 'package:practice/pages/login.dart';
import 'package:practice/pages/home.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => LoginPage(),
        '/home': (context) => HomePage(),
      }
    );
  }
}

플러터의 MaterialApp에서 제공하는 라우팅 기능은 리액트의 라우터 기능과 같이 앱 내 여러 화면 간의 이동을 구조화하고 관리할 수 있게 해준다.

routes 속성을 통해 각 화면에 경로 이름을 지정하면, 네비게이션을 할 때 해당 이름을 사용하여 페이지 이동이 가능하며, 현재 작성한 코드인 routes 설정 방식 외에도 onGenerateRoute라는 기능을 이용한 동적 라우팅, 네비게이션 스택 관리 등 다양한 라우팅 방법이 있다.

 

먼저 initialRoute는 앱이 처음 시작할 때 첫 화면으로 표시할 경로를 지정해준다.현재 ' / ' 로 되어있는데 본인은 ' / '를 로그인 페이지로 지정해놨기 때문에 처음 실행될 때 로그인 페이지가 화면에 출력된다.

리액트에선 route path에 default 값이다.

 

그리고 routes는 각 페이지별로 페이지가 보여질 경로를 정의할 때 사용된다. 이 후 지정된 경로로 이동할 경우 지정된 페이지가 화면에 출력된다. 리액트에서 라우터와 같은 기능으로 코드가 리액트에 비해 좀 더 간결해진 것 같다.

지정된 페이지로의 이동은 Navigator.pushNamed() 혹은 Navigator.push()로 작성해주면 된다.

push()와 pushNamed()의 차이는 push의 경우 위젯 자체를 넘기는 방식이고 pushNamed는 경로 이름을 전달하는 방식이다.

 

push()는 직접 위젯을 넘기며 페이지가 변환되는 방식이라 main.dart에 라우터를 작성할 필요가 없다. 구조는 다르겠지만 자바스크립트의 a 링크로 보면 된다. 그리고 push의 경우 데이터를 전달할 때 위젯의 인수에 직접 넣어 보낸다.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => HomePage(data: "Hello"),
  ),
);

 

하지만 pushNamed()는 경로 이름을 전달하기 때문에 해당 값이 지정되어 있는 라우터가 필요하다. 위 코드에서는 라우터를 작성해줬기 때문에 pushNamed로 작성해줬다. pushNamed의 경우 arguments를 통해 데이터를 전달한다.

Navigator.pushNamed(context, '/home', arguments: "Hello");

 

플러터에서의 Navigator는 페이지의 네비게이션을 stack구조로 관리하는데, 이 구조는 이전 화면으로 돌아가는 뒤로 가기 기능과 같은 네비게이션 기능을 구현할 때 사용하기 편하다.

예를 들어, Navigator.pushNamed(context, '/home');로 페이지 이동을 하면 이전 화면 위에 새 화면이 스택으로 추가되며, 뒤로 가기를 하면 최근에 추가된 화면이 제거되고 그 아래에 있던 화면으로 돌아간다. 기본적으로 뒤로가기 요소가 구현되어있다고 생각하면 된다.

 

Navigator의 주요 메소드

  • Navigator.pushNamed: 경로 이름을 사용해 새 화면을 스택에 추가한다.
  • Navigator.pop: 현재 화면을 제거하고 이전 화면으로 돌아간다.
  • Navigator.pushReplacementNamed: 현재 화면을 새 화면으로 대체하며, 스택에 현재 화면을 남기지 않는다.

 

import 'package:flutter/material.dart';
import 'home.dart';

class LoginPage extends StatelessWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text("로그인"),
              centerTitle: true,
            ),
            body: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  TextField(
                    decoration: InputDecoration(
                      labelText: "이메일",
                      border: OutlineInputBorder(),
                    ),
                    keyboardType: TextInputType.emailAddress,
                  ),
                  SizedBox(height: 16),
                  TextField(
                    decoration: InputDecoration(
                      labelText: "비밀번호",
                      border: OutlineInputBorder(),
                    ),
                    obscureText: true,
                  ),
                  SizedBox(height: 32),
                  ElevatedButton(
                    onPressed: () {
                      Navigator.pushNamed(context, '/home');
                    },
                    child: Text("로그인"),
                  )
                ],
              ),
            )
        )
    );
  }
}

위 코드는 이메일과 비밀번호를 입력하는 로그인 폼 페이지이다. 레이아웃 구조가 너무 낯설어서 적응이 잘 안된다.

최상단 틀은 Scaffold를 사용해 내장되어 있는 위젯을 사용하고, 해당 페이지의 정보를 알 수 있게 작성해논 헤더 역할의 appBar를 작성, 그리고 body는 padding으로 감싸줬다.

padding: const EdgeInsets.all(16.0),

해당 코드는 현재 padding위젯의 틀의 여백을 전체 16픽셀로 지정해주는 코드이다.

 

안쪽 틀은 세로로 여러개의 위젯을 작성할 수 있는 Column을 사용해 작성해주고 안에 이메일과 비밀번호의 입력폼을 넣었다.

TextField(
  decoration: InputDecoration(
     labelText: "이메일",
     border: OutlineInputBorder(),
  ),
  keyboardType: TextInputType.emailAddress,
),
SizedBox(height: 16),
TextField(
  decoration: InputDecoration(
    labelText: "비밀번호",
    border: OutlineInputBorder(),
  ),
  obscureText: true,
),
SizedBox(height: 32),

플러터에서 input태그는 TextField 위젯으로 작성하며, 입력창의 스타일을 정의할 수 있는 decoration 필드에 InputDecoration위젯을 사용해 스타일을 정의해줄 수 있다.

 

labelText는 input태그의 placeholder와 같은 역할을 하며, 입력창 안의 텍스트 작성 분야를 담당한다. 이 labelText는 사용자가 입력하려고 하면 해당 텍스트가 상단으로 올라가는 기능이 있는데 기본기능이 너무 야무지다. css할때 왜 이런생각을 못했을까

border는 입력 창의 테두리 부분을 제어하며, OutlineInputBorder()는 입력창 외곽에 테두리를 그려준다.

 

그리고 코드를 보면 이메일 입력과 비밀번호 입력의 하단 세팅이 다른데, 이메일의 keyboardType은 입력 창에 맞는 키보드 타입을 설정하는데, emailAddress로 설정했을 때 이메일 입력에 필요한 @나 .기호가 있는 키보드로 표시된다고 한다. 작업은 데스크탑으로 하는거라 확인은 할 수 없지만 기본적인 세팅이라고 한다.

 

비밀번호 입력창에는 obscureText 설정이 있는데, 해당 설정은 true로 했을 때 비밀번호 값이 .이나 *로 가려져서 보이게 된다. input태그에 type을 password로 설정했을 때와 같은 기능이다. 

 

ElevatedButton(
  onPressed: () {
    Navigator.pushNamed(context, '/home');
  },
  child: Text("로그인"),
)

마지막으로 로그인을 위한 이메일과 비밀번호를 보낼 버튼의 코드인데, ElevatedButton위젯은 자주 사용되는 버튼 위젯으로 그림자를 통해 입체적인 느낌을 주는 버튼 스타일이다.

onPressed 설정은 리액트의 onClick 설정과 동일하며 버튼 클릭 시의 이벤트 발생 함수를 담당한다.

위 코드는 버튼 클릭 시 현재 페이지를 /home으로 변경하는 코드이며, 라우터 이동을 위한 Navigator.pushName을 사용해 이동한다.

로그인 버튼을 누르면 메인페이지로 이동하게 된다.

해당 방식으로 페이지의 이동을 진행할 수 있으며, 이 후에 서버 연동을 통해 데이터를 받으면 데이터도 전달시킬 수 있다.

728x90

'개발 TIL' 카테고리의 다른 글

flutter 프로젝트 시작  (0) 2024.11.20
24.11.03 소프트웨어 품질 관리  (4) 2024.11.03
24.10.29 flutter 위젯 배치  (1) 2024.10.30
24.10.27 flutter 사용  (1) 2024.10.27
24.10.25 flutter 설치  (2) 2024.10.25