[英]Flutter - Using GetIt with BuildContext
我根據 flutter 文檔在我的應用程序中使用本地化。
看這里: https://flutter.dev/docs/development/accessibility-and-localization/internationalization
我使用 get_it package(版本 4.0.4)檢索 singleton 對象,如本地化委托。 不幸的是,它需要一個BuildContext
屬性。 有時在我的應用程序中我沒有上下文引用,所以如果它像這樣工作會很好: GetIt.I<AppLocalizations>()
而不是這個: AppLocalizations.of(context)
。 如果您像這樣設置 get_it,它仍然可以毫無問題地實現: GetIt.I.registerLazySingleton(() => AppLocalizations.of(context));
問題是您至少需要一次上下文才能使其工作。 此外,如果您想在初始路由中立即顯示本地化文本,則很難在需要時立即獲得正確初始化的BuildContext
。
我很難正確解釋它,所以我在一個最小的例子中重新創建了這個問題。
我注釋掉了一些會導致編譯時錯誤的代碼,但它顯示了我想象它是如何完成的。
主要.dart
GetIt getIt = GetIt.instance;
void setupGetIt() {
// How to get BuildContext properly if no context is available yet?
// Compile time error.
// getIt.registerLazySingleton(() => AppLocalizations.of(context));
}
void main() {
setupGetIt();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
// The above line also won't work. It has BuildContext but Applocalizations.of(context) won't work
// because it's above in the Widget tree and not yet setted up.
getIt.registerLazySingleton(() => AppLocalizations.of(context));
return MaterialApp(
supportedLocales: const [
Locale('en', 'US'),
Locale('hu', 'HU'),
],
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
localeResolutionCallback: (locale, supportedLocales) {
// check if locale is supported
for (final supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale?.languageCode &&
supportedLocale.countryCode == locale?.countryCode) {
return supportedLocale;
}
}
// if locale is not supported then return the first (default) one
return supportedLocales.first;
},
// You may pass the BuildContext here for Page1 in it's constructor
// but in a more advanced routing case it's not a maintanable solution.
home: Page1(),
);
}
}
初始路線
class PageBase extends StatelessWidget {
final String title;
final Widget content;
PageBase(this.title, this.content);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: content,
);
}
}
class Page1 extends PageBase {
// It won't run because I need the context but clearly I don't have it.
// And in a real app you also don't want to pass the context all over the place
if you have many routes to manage.
Page1(String title)
: super(AppLocalizations.of(context).title, Center(child: Text('Hello')));
// Intended solution
// I don't know how to properly initialize getIt AppLocalizations singleton by the time
// it tries to retrieve it
Page1.withGetIt(String title)
: super(getIt<AppLocalizations>().title, Center(child: Text('Hello')));
}
locales.dart
String globalLocaleName;
class AppLocalizations {
//AppLocalizations(this.localeName);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
static Future<AppLocalizations> load(Locale locale) async {
final String name =
locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
globalLocaleName = localeName;
return AppLocalizations();
});
}
String get title => Intl.message(
'This is the title.',
name: 'title',
);
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
// This delegate instance will never change (it doesn't even have fields!)
// It can provide a constant constructor.
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'hu'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) => AppLocalizations.load(locale);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
而一些intl生成的dart代碼和不是那么重要的.arb文件說明問題。
總而言之,在這種情況下,我如何才能在不使用上下文的情況下將我的AppLocalizations
class 用作 singleton? 也許我最初的方法不好,可以通過我所代表的其他方式來完成。 如果您有解決方案,請告訴我。
謝謝你。
要實現您所描述的內容,您需要首先使用get_it
制作導航服務。 按照以下步驟實現結果:
import 'package:flutter/material.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey =
new GlobalKey<NavigatorState>();
Future<dynamic> navigateTo(String routeName) {
return navigatorKey.currentState!
.push(routeName);
}
goBack() {
return navigatorKey.currentState!.pop();
}
}
這使您可以在整個應用程序中從任何位置導航到任何位置,而無需構建上下文。 您可以使用此導航器鍵來實現當前上下文的 AppLocalization 實例。 請參閱 FilledStacks 教程,了解這種在沒有構建上下文的情況下導航的方法。
GetIt locator = GetIt.instance;
void setupLocator() {
...
locator.registerLazySingleton(() => NavigationService());
...
}
return MaterialApp(
...
navigatorKey: navigationService.navigatorKey,
...
),
AppLocalizations
創建一個實例並導入到任何你想使用的地方localeInstance() => AppLocalizations.of(locator<NavigationService>().navigatorKey.currentContext!)!;
import 'package:{your_app_name}/{location_to_this_instace}/{file_name}.dart';
localeInstance().your_localization_variable
您可以向 MaterialApp 添加一個構建器,並在其中使用可用的上下文設置服務定位器。 例子:
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, widget) {
setUpServiceLocator(context);
return FutureBuilder(
future: getIt.allReady(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return widget;
} else {
return Container(color: Colors.white);
}
});
},
);
}
服務定位器設置:
void setUpServiceLocator(BuildContext context) {
getIt.registerSingleton<AppLocalizations>(AppLocalizations.of(context));
}
您可以將一些不可本地化的啟動畫面與FutureBuilder
和getIt.allReady()
一起使用。
就像是:
class SplashScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future: getIt.allReady(),
builder: (context, snapshot) {
if (snapshot.hasData) {
// Navigate to main page (with replace)
} else if (snapshot.hasError) {
// Error handling
} else {
// Some pretty loading indicator
}
},
);
}
我想推薦注射劑package 來處理 get_it。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.