29일차 과제 - rlatkddbs99/Flutter GitHub Wiki

  1. GetX의 여러 메소드 Android Emulator - flutter_emulator_5554 2023-03-06 16-00-05

main.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state/page/mainPage.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: mainPage(),
    );
  }
}

mainPage.dart

import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.defaultDialog(
                      title: "다이얼로그 제목",
                      content: Text("콘텐트"),
                      textConfirm: '확인',
                      textCancel: '취소'); //여러가지 설정가능
                },
                child: Text("dialog")),
            ElevatedButton(
                onPressed: () {
                  Get.snackbar("Snackbar Title", "snackbar content",
                      snackPosition: SnackPosition.TOP);
                },
                child: Text("snackbar")),
            ElevatedButton(
                onPressed: () {
                  Get.bottomSheet(Container(
                    height: 200,
                    child: Column(
                      children: [
                        Text("bottomsheet"),
                        ElevatedButton(
                            onPressed: () {}, child: const Text("닫기"))
                      ],
                    ),
                  ));
                },
                child: Text("bottomSheet")),
          ],
        ),
      ),
    );
  }
}
  1. i18n과 적용방법

i18n : 국제화. i부터 n까지 18개의 문자수를 축약해서 i18n으로 나타낸다. 국제화는 다양한 언어 및 지역에 적용할 수 있도록 프로그램을 설계하는 프로세스. 프로그램이 특정 지역이나 언어에 종속되지 않고 다양한 지역, 언어에서 정상 작동하도록 국제적으로 통용되는 sw을 설계하고 개발하는 과정

특징

  1. 현지화, 국제적인 배포에 대한 장벽을 제거하는 방식으로 설계 및 개발
  2. 현지화가 이루어질 때까지 사용할 수 없는 기능을 지원
  3. 코드가 지역, 언어 또는 문화적으로 적절하게 지원
  4. 소스코드와 콘텐츠에서 현지화 가능한 요소를 분리하여 지역에 따라 현지화된 대체적인 요소를 로드하거나 선택

적용법 지원하는 패키지는 [intl],[flutter_i18n],[easy_localization]등이 있음/ dart code를 arb로 generate 하고 변환한 arb 파일을 다시 dart로 변환하여 다국어 적용

  • arb란 Application Resource Bundle로 구글에서 만든 파일 형식

pubspec.yaml에 dependency(intl추가) 2. key로 사용할 변수들을 담은 messages.dart를 작성하겠습니다. name과 변수명은 같아

import 'package:intl/intl.dart';

class Messages {
  String get appName => Intl.message(
    "Flutter APP",
    name: "appName"
  );
  
  String get helloWorld => Intl.message(
    "Hello, World!",
    name: "helloWorld"
  );

  hello(str) => Intl.message(
      "Hello, $text!",
      name: "hello",
      args: [str]
  );
}

arb만들기 flutter pub run intl_translation:extract_to_arb --output-dir=[추출한 arb 파일이 저장될 경로] [arb를 추출할 dart 파일]

flutter pub run intl_translation:extract_to_arb --output-dir=assets/i18n lib/i18n/messages.dart

결과 -> intl_messages.arb 파일이 assets/i18n 폴더 하위에 생성 messages.dart에서 정의했던 Intl.messages()들이 json형태

  1. intl_messages.arb을 복사하여 언어별로 파일을 생성합니다. intl_en.arb intl_ko.arb

arb 파일을 직접 사용하진 못하고 플루터에서 사용할 수 있게 dart파일로 변경 flutter pub run intl_translation:generate_from_arb --output-dir=[저장될 경로] --no-use-deferred-loading [문자열이 있는 dart파일] [다국어 arb 파일들]

# windows
flutter pub run intl_translation:generate_from_arb --output-dir=lib/i18n --no-use-deferred-loading lib/i18n/messages.dart assets/i18n/intl_ko.arb assets/i18n/intl_en.arb

# mac, linux
flutter pub run intl_translation:generate_from_arb --output-dir=lib/i18n --no-use-deferred-loading lib/i18n/messages.dart assets/i18n/intl_*.arb

결과 -> lib/i18n 하위에 messages_all.dart, messages_ko.dart, messages_en.dart가 생성

다국어 적용은 LocationDelegate 클래스를 사용해야 합니다. 번역된 message들을 읽어 들이고, 어떤 언어를 지원하는지 알아내서 적용

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'messages_all.dart';

class AppLocalizations {
  static Future<AppLocalizations> load(Locale locale) {
    final String name = locale.countryCode == null ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);

    return initializeMessages(localeName).then((bool _ ) {
    Intl.defaultLocale = localeName;
    return new AppLocalizations();
    });
  }

  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }
}

class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {

  @override
  bool isSupported(Locale locale) {
    return ['en', 'ko'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) {
    return AppLocalizations.load(locale);
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) {
    return false;
  }
}

위젯적용 AppLocalizationDelegate()를 위젯에 적용 MaterialApp()의 localizationsDelegates 속성과 supportedLocales 속성을 바꿔

 localizationsDelegates: [
        AppLocalizationDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,   // https://moonsiri.tistory.com/119
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [Locale("en"), Locale("ko")],
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),

출처 : https://moonsiri.tistory.com/83

  1. GetX의 put과 find Android Emulator - flutter_emulator_5554 2023-03-06 17-34-30

main.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state/page/mainPage.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: mainPage(),
    );
  }
}

controller/app_setting_controller.dart

import 'package:get/get.dart';

class AppSettingController extends GetxController {
  bool isSoundOn;
  bool isNotificationOn;
  String appVersion;
  String appName;
  String appAuthor;
  String appPackageName;
  DateTime? lastUpdated;

  AppSettingController({
    required this.isSoundOn,
    required this.isNotificationOn,
    required this.appVersion,
    required this.appName,
    required this.appAuthor,
    required this.appPackageName,
    required this.lastUpdated,
  });
}

page/mainPage.dart

import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import 'package:state/controller/app_setting_contoller.dart';
import 'package:state/page/part_info.dart';
import 'package:state/page/whole_info.dart';

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

  @override
  Widget build(BuildContext context) {
    Get.put(AppSettingController(      //생성자와 비슷 
        isSoundOn: false,
        isNotificationOn: true,
        appVersion: "버젼",
        appName: "GetX예제",
        appAuthor: "김상윤",
        appPackageName: "state 관리",
        lastUpdated: DateTime.now()));
    return Scaffold(
      appBar: AppBar(
        title: Text("29일차 과제"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.to(PartInfo());     //페이지 이동 route역할
                },
                child: Text("부분정보")),
            ElevatedButton(
                onPressed: () {
                  Get.to(WholeInfo());
                },
                child: Text("전체 정보"))
          ],
        ),
      ),
    );
  }
}

page/part_info.dart

import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';

import '../controller/app_setting_contoller.dart';

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

  @override
  Widget build(BuildContext context) {
    var controller = Get.find<AppSettingController>();     //controller에 전역변수로 설정한 AppSetting가져오기
    return Scaffold(
      appBar: AppBar(
        title: Text("29일차 과제"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('isSoundOn : ${controller.isSoundOn}'),      // 데이터 활용
            Text('isNoficationOn : ${controller.isNotificationOn}'),
            Text('appVersion : ${controller.appVersion}'),
            Text('appName : ${controller.appName}'),
          ],
        ),
      ),
    );
  }
}

page/whole_info.dart

import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import 'package:state/controller/app_setting_contoller.dart';

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

  @override
  Widget build(BuildContext context) {
    var controller = Get.find<AppSettingController>();
    return Scaffold(
      appBar: AppBar(
        title: Text("29일차 과제"),
      ),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('isSoundOn : ${controller.isSoundOn}'),
          Text('isNoficationOn : ${controller.isNotificationOn}'),
          Text('appVersion : ${controller.appVersion}'),
          Text('appName : ${controller.appName}'),
          Text('appAuthor : ${controller.appAuthor}'),
          Text('appPackageName : ${controller.appPackageName}'),
          Text('lastUpdate : ${controller.lastUpdated}'),
        ],
      )),
    );
  }
}