【Flutter】ScreenUtilInit導入

Devlog
Devlog

 

やりたいことと課題

ScreenUtilInitの導入をするために、main()にコードを追記したい。

導入前の時点のmain()MyApp(一部割愛)。なお、MyTextMyThemeMySizeはスタイルをまとめて定義し呼び出しているものです。

Dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:electricorange/domein/00_user/state/initial_route_provider.dart';
import 'package:electricorange/infrastructure/remote_config/remote_config.dart';
import 'package:electricorange/presentation/router/main_router/router.dart';
import 'package:electricorange/presentation/router/main_router/routes.dart';
import 'package:electricorange/presentation/styles/sizes.dart';
import 'package:electricorange/presentation/styles/texts.dart';
import 'package:electricorange/presentation/styles/theme.dart';
import 'package:electricorange/firebase_options.dart';

void main() async {
  runZonedGuarded<Future<void>>(
    () async {
      // Firebaseの初期化
      WidgetsFlutterBinding.ensureInitialized();
      await MobileAds.instance.initialize();
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      );
      await RemoteConfigService().setRemoteConfig();
      // 画面の向き
      await SystemChrome.setPreferredOrientations([
        // 縦向き
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
      ]);
      // Flutterフレームワーク内でスローされたすべてのエラーを自動的にキャッチ
      FlutterError.onError =
          FirebaseCrashlytics.instance.recordFlutterFatalError;
      runApp(const ProviderScope(child: MyApp()));
    },
    // Flutterフレームワーク内でキャッチされないエラー
    (error, stack) async => await FirebaseCrashlytics.instance.recordError(
      error,
      stack,
      fatal: true,
    ),
  );
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 割愛 initialLocation(ユーザーのログイン状態や初回起動かによって起動画面を出しわけ)
    // 割愛 router(Providerで受け取る形にして別の場所で定義)

    final app = MaterialApp.router(
      routeInformationProvider: router.routeInformationProvider,
      routeInformationParser: router.routeInformationParser,
      routerDelegate: router.routerDelegate,
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      theme: ThemeData(
        useMaterial3: true,
        fontFamily: 'MPLUS1p',
        colorSchemeSeed: MyTheme.green,
        scaffoldBackgroundColor: MyTheme.background,
        navigationBarTheme: NavigationBarThemeData(
          backgroundColor: MyTheme.onGreen,
          indicatorColor: MyTheme.green,
          surfaceTintColor: MyTheme.grey,
          height: MySize.navigationBarHeight,
          iconTheme: WidgetStateProperty.resolveWith((states) {
            return IconThemeData(size: MySize.navigationIconSize);
          }),
          labelTextStyle: WidgetStateProperty.resolveWith((states) {
            return MyText.navi;
          }),
        ),
        pageTransitionsTheme: const PageTransitionsTheme(
          builders: <TargetPlatform, PageTransitionsBuilder>{
            TargetPlatform.android: CupertinoPageTransitionsBuilder(), // iOS風
            TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
          },
        ),
      ),
      supportedLocales: const [
        // Locale("en"),
        Locale("ja"),
      ],
      debugShowCheckedModeBanner: false, // タグ非表示
    );

    return MediaQuery(
    data: MediaQuery.of(context).copyWith(
     textScaler: TextScaler.linear(1),
     boldText: false,
    ), // 文字サイズを固定
    child: app,
  );
  }
}


すでにmain()MyAppでは以下を実行している中、てんこ盛り状態のどこに導入すれば良いのかの備忘です。

  • Firebaseを初期化して
  • RemoteConfigを初期化して
  • Crashlyticsを設定して
  • 画面の向きを固定して
  • 文字サイズを指定して
  • ProviderScopeで囲んで
  • ・・・
 

サンプルコードでの実装記事が多かったため、実際のコードではどこに入れれば良いかわからなかったので、順番に挿入してみたよ

  

まずは結論。これで解決

Dart
// 追加
import 'package:flutter_screenutil/flutter_screenutil.dart';

void main() async {
  // 変更なし
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    return ScreenUtilInit(
      designSize: const Size(411, 890), // 基準サイズ
      minTextAdapt: true, // テキストサイズの適応を有効化
      splitScreenMode: true, // マルチウィンドウ対応
      builder: (context, child) {
        return MaterialApp.router(
        // 割愛
          builder: (context, child) => MediaQuery(
            data: MediaQuery.of(context).copyWith(
              textScaler: TextScaler.linear(1),
              boldText: false,
            ), // 文字サイズを固定
            child: child!,
          ),
        );
      },
    );
  }
}

 

以下別パターン

原因がよくわかっていなくて申し訳ないのですが、変更した瞬間はどれも動いたためそのうちの一つでしばらくUIテストをしていたのですが、突然キーボードがクラッシュする不具合に悩まされ、結果的にはScreenUtilInitが原因でした。
詳細はこちら→https://hami030.com/devlog/flutter-error-textfield/

以下のいずれも一時的には動きますが、遅れて不具合が起こる可能性はなきにしもあらず。

 

よくわかっていないのでとっても怖い。

1. とりあえずrunAppに書いてみる

とりあえずrunAppに書いている記事が多いので記載。動く。

Dart
runApp(
 ScreenUtilInit(
  designSize: Size(411, 890),
  builder: (BuildContext context, Widget? widget) => const ProviderScope(child: MyApp()),
 ),
);


次にこれ。一旦は動いたのでしばらくこの実装にしていたのだが、少しして発生したキーボードクラッシュエラーの原因がこれでした。ので結果的にはこれはNG。

Dart
runApp(
  ProviderScope(
    child: ScreenUtilInit(
      designSize: Size(411, 890),
      builder: (context, child) {
        return child!;
      },
      child: MyApp(),
    ),
  ),
);

 

2. MyAppに書いてみる

runAppは戻して・・・

Dart
runApp(const ProviderScope(child: MyApp()));


MyAppで呼び出してみます。どっちでも動く。

Dart
return ScreenUtilInit(
    designSize: Size(411, 890),
    builder: (context, child) {
      return MediaQuery(
        data: MediaQuery.of(context).copyWith(
          textScaler: TextScaler.linear(1),
          boldText: false,
        ), // 文字サイズを固定
        child: app,
      );
    },
  );

 

Dart
return MediaQuery(
  data: MediaQuery.of(context).copyWith(
    textScaler: TextScaler.linear(1),
    boldText: false,
  ), // 文字サイズを固定
  child: ScreenUtilInit(
    designSize: Size(411, 890),
    builder: (context, child) => app,
  ),
);

 

コメント

タイトルとURLをコピーしました