Flutter 화면 전환(복수 파일 이용)

|

Flutter에서의 화면 전환 예제를 여러 개의 파일로 나누어서 호출하도록 변경했습니다. 다른 파일을 가져올 때 다음과 같이 두 가지 방식으로 import 할 수 있습니다.

import 'first_screen_widget.dart';
import 'package:snowdeer_hello_flutter/second_screen_widget.dart';


main.dart

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

void main() => runApp(SnowDeerApp());

class SnowDeerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SnowDeer App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.deepPurple,
      ),
      home: FirstScreenWidget(),
    );
  }
}


first_screen_widget.dart

import 'package:flutter/material.dart';
import 'package:snowdeer_hello_flutter/second_screen_widget.dart';

class FirstScreenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.amber,
          child: Center(
              child: RaisedButton(
            child: Text('Move to Second Screen'),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => SecondScreenWidget()),
              );
            },
          ))),
    );
  }
}


second_screen_widget.dart

import 'package:flutter/material.dart';

class SecondScreenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.green,
          child: Center(
              child: RaisedButton(
              child: Text('Back to First Screen'),
              onPressed: () {
                Navigator.pop(context);
              },
          ))),
    );
  }
}

Flutter 화면 전환

|

Flutter에서 화면 전환을 하는 예제입니다. Navigator를 이용해서 새로운 화면을 push 또는 pop 하여 화면간 전환을 합니다.

main.dart

import 'package:flutter/material.dart';

void main() => runApp(SnowDeerApp());

class SnowDeerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SnowDeer App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.deepPurple,
      ),
      home: FirstScreenWidget(),
    );
  }
}

class FirstScreenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.amber,
          child: Center(
              child: RaisedButton(
            child: Text('Move to Second Screen'),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => SecondScreenWidget()),
              );
            },
          ))),
    );
  }
}

class SecondScreenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.green,
          child: Center(
              child: RaisedButton(
            child: Text('Back to First Screen'),
            onPressed: () {
              Navigator.pop(context);
            },
          ))),
    );
  }
}


화면간 데이터 전달하는 방법

아래와 같이 사용자 정의 클래스를 만들고 해당 인스턴스를 다음 화면에 전달하는 예제입니다.

class Item {
  int id;
  String name;

  Item({this.id, this.name});
}


전체 코드

import 'package:flutter/material.dart';

void main() => runApp(SnowDeerApp());

class SnowDeerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SnowDeer App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.deepPurple,
      ),
      home: FirstScreenWidget(),
    );
  }
}

class Item {
  int id;
  String name;

  Item({this.id, this.name});
}

class FirstScreenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.amber,
          child: Center(
              child: RaisedButton(
            child: Text('Move to Second Screen'),
            onPressed: () {
              final item = Item(id: 10, name: 'snowdeer');
              Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => SecondScreenWidget(item: item)),
              );
            },
          ))),
    );
  }
}

class SecondScreenWidget extends StatelessWidget {
  final Item item;

  SecondScreenWidget({this.item});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Screen"),
      ),
      body: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.green,
          child: Center(
            child: Text('id: ${item.id}, name: ${item.name}'),
          )),
    );
  }
}

위에서 두 번째 위젯인 SecondScreenWidget의 생성자를 통해서 item 인스턴스를 속성에 넣어주도록 했습니다.

생성자는 아래와 같이 필수 입력 매개변수로 선언하면 좀 더 안전한 코드가 됩니다.

SecondScreenWidget({@required this.item});

Flutter Widget을 이용해 로그인 화면 배치해보기

|

로그인 화면 배치

Image

main.dart

import 'package:flutter/material.dart';

void main() => runApp(SnowDeerExample());

class SnowDeerExample extends StatelessWidget {
  static const title = 'SnowDeer\'s Login Example';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: title,
        debugShowCheckedModeBanner: false,
        home: Scaffold(
//            appBar: AppBar(title: Text(title)),
            body: Container(
              margin: EdgeInsets.symmetric(horizontal: 40),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Container(
                    child: Image.asset(
                      'assets/images/snowdeer.png',
                      width: 160,
                      height: 160,
                    ),
                  ),
                  Container(
                      margin: EdgeInsets.only(top: 20),
                      child: TextFormField(
                        keyboardType: TextInputType.emailAddress,
                        initialValue: 'snowdeer0314@gmail.com',
                        decoration: InputDecoration(
                          border: OutlineInputBorder(),
                        ),
                      )),
                  Container(
                      margin: EdgeInsets.only(top: 8),
                      child: TextFormField(
                        obscureText: true,
                        decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          hintText: 'Input password',
                        ),
                      )),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      RaisedButton(
                        child: Text("Login"),
                        onPressed: () => {print("LoginButton is Clicked.")},
                      ),
                      SizedBox(
                        width: 8,
                      ),
                      RaisedButton(
                        child: Text("Cancel"),
                        onPressed: () => {print("CancelButton is Clicked.")},
                      )
                    ],
                  )
                ],
              ),
            )));
  }
}

Flutter ListView Widget 예제

|

ListView Widget 예제

import 'package:flutter/material.dart';

void main() => runApp(SnowDeerExample());

class SnowDeerExample extends StatelessWidget {
  static const title = 'SnowDeer\'s ListView Example';
  static const List list = [
    'snowdeer',
    'ran',
    'song',
    'yang',
    'john',
    'downy',
    'gap',
    'kyu',
    'ho',
    'hoon',
  ];

  Widget buildListView() {
    return ListView.builder(
        itemCount: list.length,
        itemBuilder: (BuildContext context, int i) {
          return ListTile(
            title: Text(
              list[i],
            ),
            trailing: Icon(Icons.favorite_border),
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: title,
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          appBar: AppBar(title: Text(title)),
          body: buildListView(),
        ));
  }
}

Flutter Layout Widget 예제(Container, Row, Column)

|

Container Widget 예제

Container 위젯은 자식을 1개를 갖는 위젯입니다.

import 'package:flutter/material.dart';

void main() => runApp(SnowDeerExample());

class SnowDeerExample extends StatelessWidget {
  static const title = 'SnowDeer\'s Container Example';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: title,
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            appBar: AppBar(title: Text(title)),
            body: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Container(
                    child: Text('첫 번째 Container'),
                    color: Colors.yellow,
                  ),
                  Container(
                    child: Text('두 번째 Container with padding(EdgeInsets.only)'),
                    padding: EdgeInsets.only(
                        left: 12, top: 12, bottom: 12, right: 12),
                    color: Colors.blueGrey,
                  ),
                  Container(
                    child: Text(
                        '세 번째 Container with padding(EdgeInsets.symmetric)'),
                    padding: EdgeInsets.symmetric(vertical: 12, horizontal: 20),
                    color: Colors.deepOrange,
                  ),
                  Container(
                    child: Text(
                        '네 번째 Container with margin(EdgeInsets.symmetric)'),
                    margin: EdgeInsets.symmetric(vertical: 12, horizontal: 20),
                    color: Colors.cyan,
                  ),
                ])));
  }
}


Row/Column Widget 예제

Row 위젯은 자식 위젯들을 가로로 배치할 때 사용합니다. 반대로 Column은 자식 위젯들을 세로로 배치할 때 사용합니다.

import 'package:flutter/material.dart';

void main() => runApp(SnowDeerExample());

class SnowDeerExample extends StatelessWidget {
  static const title = 'SnowDeer\'s Row Example';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: title,
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            appBar: AppBar(title: Text(title)),
            body: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    child: Text('첫 번째 Container'),
                    color: Colors.yellow,
                  ),
                  Container(
                    child: Text('두 번째 Container with padding(EdgeInsets.only)'),
                    padding: EdgeInsets.only(
                        left: 12, top: 12, bottom: 12, right: 12),
                    color: Colors.blueGrey,
                  ),
                  RaisedButton(
                    child: Text('Hello'),
                  )
                ])));
  }
}


Row/Column Widget 속성

RowColumn은 레이아웃 위젯이다보니 중요한 속성들이 있습니다. mainAxisAlignment는 현재 속성의 축(axis)을 기준으로 정렬을 하는 옵션입니다. 현재 레이아웃이 Row이면, 가로 방향을 의미하기 때문에 좌/우 정렬값을 의미합니다. MainAxisAlignment.start, MainAxisAlignment.center 등의 값을 가질 수 있습니다.

crossAxisAlignment는 현재 속성의 반대 방향으로 정렬을 의미합니다.

예를 들어 아래 속성이면 다음 그림과 같이 위젯이 배치됩니다.

  body: Column(
    mainAxisAlignment: MainAxisAlignment.start,
    crossAxisAlignment: CrossAxisAlignment.end,
    ...

Image


  body: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.start,
    ...

Image


  body: Column(
    mainAxisAlignment: MainAxisAlignment.end,
    crossAxisAlignment: CrossAxisAlignment.start,
    ...

Image


  body: Row(
    mainAxisAlignment: MainAxisAlignment.start,
    crossAxisAlignment: CrossAxisAlignment.end,
    ...

Image


  body: Row(
    mainAxisAlignment: MainAxisAlignment.start,
    crossAxisAlignment: CrossAxisAlignment.center,
    ...

Image