[Flutter GetX : 01] 환경 설정, 라우트 관리, Argments, transition, 동적 url 전달

728x90

환경 설정, 라우트 관리, Argments, transition, 동적 url 전달

 

목차
1. GetX의 장점
2. 세팅 하기
3. 라우트 관리
4. transition
5. Argments 전달
6. 동적 url 전달

 

1. GetX의 장점

Flutter를 위한 매우 가볍고 강력한 라이브러리이며 강력함을 뒷받침 하고 있는 3가지 기본 원칙이 있으며 다음과 같습니다.

첫째. 생산성 

 - 간결하게 표현할 수 있습니다.

 - 컨트롤러들을 사용하고 반환시켜주는 처리를 신경 쓰지 않아도 알아서 GetX에서 사용되지 않을 때 제거해주기 때문에 개발자분들은 더욱더 개발에만 신경 쓸 수 있습니다.

둘째. 성능

 - GetX는 성능과 최소한의 리소스 소비에 중점을 둡니다.

 - GetX는 Streams나 ChangeNotifier를 사용하지 않습니다.

 - 최소의 재 빌드를 위해 똑똑한 알고리즘을 적용하기 위해, GetX는 상태가 변했는지 확인하는 comparator를 사용합니다.

셋째. 조직화  

 - GetX는 화면, 비즈니스 로직, 종속성 주입 및 내비게이션을 완전히 분리하여 관리할 수 있습니다.

 -  GetX는 자체 종속성 주입 기능을 사용하여 DI를 뷰에서 완전히 분리하기 때문에 다중 Provider를 통해 위젯 트리에서 컨트롤러/모델/블록으로 주입할 필요가 없습니다

 - GetX를 사용하면 기본적으로 클린 코드를 가지게 되어 애플리케이션의 각 기능을 쉽게 찾을 수 있습니다. 이것은 유지 보수를 용이하게 하며 모듈의 공유가 가능하고 Flutter에서는 생각할 수 없었던 것들도 전부 가능합니다.

 

2. 세팅 하기

 

pubspec.yaml 파일에 다음 소스 추가로 프로젝트에 라이브러리를 추가한다.

dependencies:
    get: ^3.24.0

 

main.dart로 들어가서 return MaterialApp 부분을 return GetMaterialApp으로 바꿔주기만 하면 된다.

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

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Home(),
   	);
  }
}

 

다음과 같이 한 줄로 줄여버릴 수도 있다.

void main() => runApp(GetMaterialApp(home: Home()));

GetMaterialApp은 상태 관리 목적 이외에도 라우트 관리, 스낵바, 국제화, bottomSheets, 다이얼로그 등 많은 기능들을 지원한다.

 

 

3. 라우트 관리

 

아래는 기존의 방법으로 페이지를 이동하기 위한 소스이다.

Navigator.of(context).push(
  MaterialPageRoute(
 	 builder: (BuildContext context) => HomePage(),
  ),
);

 

간단한 작업임에도 불구하고 MaterialPageRoute와 context를 전달해줘야 하는 복잡함이 있었는데 GetX에서는 아래의 짧은 코드로 같은 기능을 수행할 수 있게 해준다.

 

Get.to(HomePage());

아래는 위의 코드를 활용한 예시 코드이다.

 

(lib/src/home.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/normal/first.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.to(() => const FirstPage()); // Get.to(FistPage())도 가능하지만 왼쪽 방식을 권장한다.
                },
                child: Text("일반적인 라우트"),
            )
          ]
        )
      )
    );
  }
}

 

home 위젯에 있는 버튼을 누르면 FirstPage 위젯으로 이동할 수 있을 것이다.

 

 

라우트 이름을 붙이는 방식으로도 관리를 할 수 있는 방법이 있다.

 

아래 코드는 좀 전에 보았던 이름이 없는 경우의 관리 방식이다.

HomePage라는 위젯이 있는 페이지로 이동하게 된다.

Get.to(HomePage());

아래는 이름을 붙이는 방법의 예시이다.

Get.toNamed("/Home");

 

먼저 main.dart에서 페이지 마다 이름을 붙여 보도록 한다.

 

페이지에 이름 설정하기

GetPage(name: "/second", page: () => const 이동할 위젯 이름())

 

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/home.dart';
import 'package:flutter_getx/src/pages/normal/first.dart';
import 'package:get/get.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      initialRoute: "/",
      getPages: [
        GetPage(name: "/", page: () => const Home()),
        GetPage(name: "/first", page: () => const FirstNamedPage()),
      ],
    );
  }
}

 

 

(lib/src/home.dart)에 이름있는 라우트 방식을 활용한 버튼을 하나 만들어 보았다.

 

이름있는 라우터 방식으로 페이지 이동하기.

Get.toNamed("페이지 name");
import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/normal/first.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.to(() => const FirstNamedPage());
                },
                child: Text("일반적인 라우트"),
            ),
            ElevatedButton(
              onPressed: () {
                Get.toNamed("/first");
              },
              child: Text("Named 라우트"),
            )
          ]
        )
      )
    );
  }
}

Named 라우트 버튼을 클릭하면 일반적인 라우트 버튼을 클릭한 것과 마찬가지로 first 위젯으로 이동할 수 있게 되었다.

 

 

위의 방식들은 이전의 페이지가 제대로 닫기지 않는다는 단점이 있다.

페이지를 닫는 방식은 대표적으로 두가지가 있다.

Get.offNamed("/second");  // 현재 창을 닫고 해당 페이지로 이동
Get.offAllNamed("/");	// 열린 페이지를 전부 닫고 해당 페이지로 이동

전자의 경우 스플래시 및 로그인 화면에 이용하면 좋고, 후자의 경우 장바구니와 투표 등에 이용하면 좋다.

 

 

4. transition

페이지 전환 효과를 간편하게 지정할 수 있다.

다양한 기능을 제공하고 있다.

main.dart의 페이지 설정 부분을 다음과 같이 수정해보았다.

initialRoute: "/",
      getPages: [
        GetPage(name: "/", page: () => const Home(), transition: Transition.zoom),
        GetPage(name: "/first", page: () => const FirstNamedPage(), transition: Transition.zoom),
        GetPage(name: "/second", page: () => const SecondNamedPage(), transition: Transition.zoom),
      ],

모든 페이지의 transition 설정 부분에 zoom 효과를 적용한 것이다.

transition을 적용할 경우, 실행중인 앱을 새로고침해야 변경 사항을 확인할 수 있다.

이제 어느 페이지를 이동하더라도 zoom효과가 적용되는 것을 확인할 수 있을 것이다.

 

참고로 모든 페이지에 같은 transition 효과를 적용하고 싶으면 아래의 코드로 작성하는 것이 더 효율적이다.

defaultTransition으로 모든 페이지에 대한 기본 설정을 한번에 적용할 수 있다.

return GetMaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
    visualDensity: VisualDensity.adaptivePlatformDensity,
  ),
  initialRoute: "/",
  defaultTransition: Transition.zoom,
  getPages: [
    GetPage(name: "/", page: () => const Home()),
    GetPage(name: "/first", page: () => const FirstNamedPage()),
  ],
);

 

5. Argments 전달

 

페이지간에 인수를 주고 받을 수 있는 기능을 제공한다.

아래는 /first라는 이름을 가진 페이지로 "똥"이라는 인수 값을 전달하는 코드이다.

Get.toNamed("/first", arguments: "똥");

아래는 해당 페이지에서 인수 값을 받는 코드이다.

Get.arguments

 

예시 코드 : 버튼을 누르면 인수 값으로 텍스트를 넘기고, 받는 쪽 페이지에서 인수를 받아 Text위젯으로 출력하는 예제.

(main.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/home.dart';
import 'package:flutter_getx/src/pages/normal/first.dart';
import 'package:flutter_getx/src/pages/normal/second.dart';
import 'package:get/get.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      initialRoute: "/",
      getPages: [
        GetPage(name: "/", page: () => const Home(), transition: Transition.zoom),
        GetPage(name: "/first", page: () => const FirstNamedPage(), transition: Transition.zoom),
      ],
    );
  }
}

(lib/src/home.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/normal/first.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.toNamed("/first", arguments: "똥");
                },
                child: const Text("Argment 전달"),
            ),
          ]
        )
      )
    );
  }
}

(lib/src/pages/normal/first.dart)

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("First Named Page"),
      ),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text("${Get.arguments}"),
                ]
            )
        )
    );
  }
}

인수값이 정상적으로 넘어갔음을 확인할 수 있다.

Argments 값으로는 텍스트, 정수, Map, 심지어 개발자가 커스텀 한 객체까지 넘길 수 있다!

아래는 커스텀 객체를 넘기는 예제 코드이다.

(lib/src/home.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/normal/first.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.toNamed("/first", arguments: User(
                    name: "이순신",
                    age: 30,
                  ));
                },
                child: const Text("Argment 전달"),
            ),
          ]
        )
      )
    );
  }
}

class User {
  String? name;
  int? age;
  User({this.name, this.age});
}

(lib/src/pages/normal/first.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/home.dart';
import 'package:flutter_getx/src/pages/normal/second.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("First Named Page"),
      ),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text("${(Get.arguments as User).name} : ${(Get.arguments as User).age.toString()}"),
                ]
            )
        )
    );
  }
}

(참고로 Text위젯은 기본적으로 String 객체를 받기 때문에 int로 선언한 age값을 인수로 받을 때 toString() 메서드로 형변환 해주는 것이 좋다. 'type 'int' is not a subtype of type 'User' in type cast' 와 같은 에러가 발생할 수 있기 때문이다.)

 

 

6. 동적 url 전달

 

Argments 뿐만 아니라 url 주소까지도 전달할 수 있다.

예를들어, 아래와 같은 방식으로 url 주소를 넘긴다고 가정하자.

Get.toNamed("/user/1234?name=이순신&age=30");

Get.parameters와 key값을 활용하면 별다른 코드를 작성할 필요없이 아주 간단하게 값을 받는 쪽에서 uid=1234, name=이순신, age=30형태로 할당 받을 수 있다.

Text("${Get.parameters['uid']}"),
Text("${Get.parameters['name']}님 안녕하세요!"),
Text("${Get.parameters['age']}살 이시군요?"),

아래는 예시 코드이다.

(main.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/home.dart';
import 'package:flutter_getx/src/pages/normal/user.dart';
import 'package:get/get.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      initialRoute: "/",
      defaultTransition: Transition.zoom,
      getPages: [
        GetPage(name: "/", page: () => const Home()),
        GetPage(name: "/user/:uid", page: () => const UserPage()),
      ],
    );
  }
}

(lib/src/pages/home.dart)

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.toNamed("/user/1234?name=이순신&age=30");
                },
                child: const Text("동적 Url 전달"),
            ),
          ]
        )
      )
    );
  }
}

(lib/pages/normal/user.dart)

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("User Page"),
      ),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text("${Get.parameters['uid']}"),
                  Text("${Get.parameters['name']}님 안녕하세요!"),
                  Text("${Get.parameters['age']}살 이시군요?"),
                ]
            )
        )
    );
  }
}

 

728x90