当我需要在flutter应用程序中设置标题以及此类时,如何在不在路线上启动(上下文)解决这个问题?
我的Flutter应用程序具有几种语言的翻译,但是直到我将路线引入了我的应用程序以进行导航,这很好。现在,我总是会发现我要设置的文本是无效的问题,在我看来,当应用程序试图访问它们时,尚未启动文本或翻译。似乎我可以在这里使用“晚”修饰符,尽管在这个问题上进行了很多谷歌搜索,并试图适应许多发现的解决方案,但我无法让我的应用程序再工作了。
我只使用Flutter工作了几个星期,所以这对我来说仍然很新,我想我遇到问题的部分原因是,也许我还不完全理解Flutter的处理方式吗?
无论如何,这是我的主要代码:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Flutter App',
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''), // English
Locale('es', ''), // Spanish
Locale('de', ''), // German
Locale('fr', ''), // Frensh
Locale('nb', ''), // Norweigian
Locale('sv', '') // Swedish
],
theme: MyTheme.lightTheme,
// theme: ThemeData(
// primarySwatch: Colors.blue,
// ),
home: const MyHomePage(title: "My home page"),
);
}
}
MyHomePage:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
NewLogPage(title: 'New Log'), //these will need translations eventually too
ReadLogPage(title: 'Read Log'),//these will need translations eventually too
SettingsPage(title: "Settings"),//these will need translations eventually too
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: ImageIcon(AssetImage("bottomnav_new_log_inactive.png")),
activeIcon: ImageIcon(AssetImage("bottomnav_new_log_active.png")),
label:'New Log'
),
BottomNavigationBarItem(
icon: ImageIcon(AssetImage("bottomnav_read_log_inactive.png")),
activeIcon: ImageIcon(AssetImage("bottomnav_read_log_active.png")),
label: 'Read Tracer',
backgroundColor: Colors.green,
),
BottomNavigationBarItem(
icon: ImageIcon(AssetImage("bottomnav_settings_inactive.png")),
activeIcon: ImageIcon(AssetImage("bottomnav_settings_active.png")),
label: 'Settings',
backgroundColor: Colors.purple,
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
showSelectedLabels: false,
showUnselectedLabels: false,
onTap: _onItemTapped,
),
);
}
}
新日志页面:
class NewLogPage extends StatefulWidget {
const NewLogPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<NewLogPage> createState() => _NewLogPageState();
}
class _NewLogPageState extends State<NewLogPage> {
@override
Widget build(BuildContext context) {
return MaterialApp(
routes:{
'/' : (context) => NewLogSelector(),
'/newLogScanner' : (context) => NewLogScanner(),
},
theme: MyTheme.lightTheme,
);
}
}
最后我的选择器窗口小部件
class NewLogSelector extends StatefulWidget {
const NewLogSelector({Key? key}) : super(key: key);
@override
State<NewLogSelector> createState() => _NewLogSelectorState();
}
class _NewLogSelectorState extends State<NewLogSelector> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
toolbarHeight: MyDimensions.appBarHeight,
flexibleSpace: FlexibleSpaceBar(
centerTitle: false,
titlePadding: EdgeInsetsDirectional.only(
start: MyDimensions.startMargin,
bottom: 0.0,
top: MyDimensions.topMargin,
),
title: Column(
children: [
Text(
AppLocalizations.of(context)!.title_new_log, // <= not working, null
style: MyTextStyle.lightSubHeader,
),
SizedBox(height: MyDimensions.titlePadding),
Text(
// AppLocalizations.of(context)!.instruction_select_product, <= not working, null
"text", <=working just fine
style: MyTextStyle.lightHeader,
),
],
crossAxisAlignment: CrossAxisAlignment.start,
),
),
actions: <Widget> [
IconButton(
icon: const Icon(Icons.refresh),
color: Colors.white,
onPressed: (){
setState(() {
});
},
),
],
bottom: TabBar(
tabs: [
Tab(text: AppLocalizations.of(context)!.title_general_tab), // <= not working, null
Tab(text: AppLocalizations.of(context)!.title_specific_tab), // <= not working, null
],
),
),
body: TabBarView(
children: [
ListView.builder(
itemCount: 3,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text("General ${index+1}"),
onTap: () {
Navigator.pushNamed(context, '/newLogScanner');
},
),
);
},
),
ListView.builder(
itemCount: 4,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text("Specific ${index+1}"),
onTap: () {
Navigator.pushNamed(context, '/newLogScanner');
},
),
);
},
),
],
),
),
);
}
,因此有关如何解决此问题的任何建议?
编辑: 我的鼓掌化课程按要求(尽管很长,但由于涉及到很长的时间):
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_de.dart';
import 'app_localizations_en.dart';
import 'app_localizations_es.dart';
import 'app_localizations_fr.dart';
import 'app_localizations_nb.dart';
import 'app_localizations_sv.dart';
abstract class AppLocalizations {
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('de'),
Locale('en'),
Locale('es'),
Locale('fr'),
Locale('nb'),
Locale('sv')
];
// translated phrases here, but removed since it is too long
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) => <String>['de', 'en', 'es', 'fr', 'nb', 'sv'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'de': return AppLocalizationsDe();
case 'en': return AppLocalizationsEn();
case 'es': return AppLocalizationsEs();
case 'fr': return AppLocalizationsFr();
case 'nb': return AppLocalizationsNb();
case 'sv': return AppLocalizationsSv();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.'
);
}
My flutter app has translations to several languages but that was working fine until I introduced routes to my app for navigation between screens. Now I always get the issue that the texts I'm trying to set are null and it seems to me that the reason for this is that the texts or translations are not initiated yet when the app tries to access them. It doesn't seem like I can use the 'late' modifier here, and despite having googled quite a bit on this issue and trying to adapt many of the solutions found I can't get my app to work any more.
I've only been working with flutter for a few weeks so it's still fairly new to me, and I guess part of the reason I have problems with this is that maybe I don't fully understand the way flutter handles things yet?
Anyway, here's the code for my main:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Flutter App',
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''), // English
Locale('es', ''), // Spanish
Locale('de', ''), // German
Locale('fr', ''), // Frensh
Locale('nb', ''), // Norweigian
Locale('sv', '') // Swedish
],
theme: MyTheme.lightTheme,
// theme: ThemeData(
// primarySwatch: Colors.blue,
// ),
home: const MyHomePage(title: "My home page"),
);
}
}
MyHomePage:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
NewLogPage(title: 'New Log'), //these will need translations eventually too
ReadLogPage(title: 'Read Log'),//these will need translations eventually too
SettingsPage(title: "Settings"),//these will need translations eventually too
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: ImageIcon(AssetImage("bottomnav_new_log_inactive.png")),
activeIcon: ImageIcon(AssetImage("bottomnav_new_log_active.png")),
label:'New Log'
),
BottomNavigationBarItem(
icon: ImageIcon(AssetImage("bottomnav_read_log_inactive.png")),
activeIcon: ImageIcon(AssetImage("bottomnav_read_log_active.png")),
label: 'Read Tracer',
backgroundColor: Colors.green,
),
BottomNavigationBarItem(
icon: ImageIcon(AssetImage("bottomnav_settings_inactive.png")),
activeIcon: ImageIcon(AssetImage("bottomnav_settings_active.png")),
label: 'Settings',
backgroundColor: Colors.purple,
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
showSelectedLabels: false,
showUnselectedLabels: false,
onTap: _onItemTapped,
),
);
}
}
The new log page:
class NewLogPage extends StatefulWidget {
const NewLogPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<NewLogPage> createState() => _NewLogPageState();
}
class _NewLogPageState extends State<NewLogPage> {
@override
Widget build(BuildContext context) {
return MaterialApp(
routes:{
'/' : (context) => NewLogSelector(),
'/newLogScanner' : (context) => NewLogScanner(),
},
theme: MyTheme.lightTheme,
);
}
}
And finally my selector widget
class NewLogSelector extends StatefulWidget {
const NewLogSelector({Key? key}) : super(key: key);
@override
State<NewLogSelector> createState() => _NewLogSelectorState();
}
class _NewLogSelectorState extends State<NewLogSelector> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
toolbarHeight: MyDimensions.appBarHeight,
flexibleSpace: FlexibleSpaceBar(
centerTitle: false,
titlePadding: EdgeInsetsDirectional.only(
start: MyDimensions.startMargin,
bottom: 0.0,
top: MyDimensions.topMargin,
),
title: Column(
children: [
Text(
AppLocalizations.of(context)!.title_new_log, // <= not working, null
style: MyTextStyle.lightSubHeader,
),
SizedBox(height: MyDimensions.titlePadding),
Text(
// AppLocalizations.of(context)!.instruction_select_product, <= not working, null
"text", <=working just fine
style: MyTextStyle.lightHeader,
),
],
crossAxisAlignment: CrossAxisAlignment.start,
),
),
actions: <Widget> [
IconButton(
icon: const Icon(Icons.refresh),
color: Colors.white,
onPressed: (){
setState(() {
});
},
),
],
bottom: TabBar(
tabs: [
Tab(text: AppLocalizations.of(context)!.title_general_tab), // <= not working, null
Tab(text: AppLocalizations.of(context)!.title_specific_tab), // <= not working, null
],
),
),
body: TabBarView(
children: [
ListView.builder(
itemCount: 3,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text("General ${index+1}"),
onTap: () {
Navigator.pushNamed(context, '/newLogScanner');
},
),
);
},
),
ListView.builder(
itemCount: 4,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text("Specific ${index+1}"),
onTap: () {
Navigator.pushNamed(context, '/newLogScanner');
},
),
);
},
),
],
),
),
);
}
So Any suggestions regarding how I can get around this issue?
EDIT:
My AppLocalizations class as requested (although abreviated since it's fairly long):
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_de.dart';
import 'app_localizations_en.dart';
import 'app_localizations_es.dart';
import 'app_localizations_fr.dart';
import 'app_localizations_nb.dart';
import 'app_localizations_sv.dart';
abstract class AppLocalizations {
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('de'),
Locale('en'),
Locale('es'),
Locale('fr'),
Locale('nb'),
Locale('sv')
];
// translated phrases here, but removed since it is too long
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) => <String>['de', 'en', 'es', 'fr', 'nb', 'sv'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'de': return AppLocalizationsDe();
case 'en': return AppLocalizationsEn();
case 'es': return AppLocalizationsEs();
case 'fr': return AppLocalizationsFr();
case 'nb': return AppLocalizationsNb();
case 'sv': return AppLocalizationsSv();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.'
);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的
myHomePage
执行此操作:static const List&lt; widget&gt; _widgetOptions = [...构建窗口小部件...]
基本上要求编程语言构造该列表,一次是类构建的一部分 - 这很可能在您的程序开始运行之前就会发生。
但实际上,这不应该是静态const列表,对吗?因为您只在运行时知道本地化将是什么。因此,您想动态构造该列表,而不是静态构造。
因此,我想知道,如果在
_MyHomePagestate
中,您将其更改为:晚列表&lt; widget&gt; _widgetOptions;
然后介绍了这一点:
因此,现在我在构造小部件时在运行时构造该列表。我认为这是类似的东西.....
Your
MyHomePage
does this:static const List<Widget> _widgetOptions = [...construct widgets...]
That's basically asking the programming language to construct that list, once, as part of class construction - which may well happen before your program starts running.
But in truth, that shouldn't be a static const list, right? Because you only know at runtime what the localisation will be. So you want to construct that list dynamically, not statically.
So I wonder what will happen if, in
_MyHomePageState
, you changed it to:late List<Widget> _widgetOptions;
and then introduced this:
So now I'm constructing that list at runtime, when the widget is being constructed. I think it's something subtle like that.....