效果图,代码注释全。
首先
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_localizations:
sdk: flutter
shared_preferences: ^2.2.0
dev_dependencies:
flutter_test:
sdk: flutter
这是一个pubspec.yaml文件中的代码示例,用于声明Flutter应用程序所需的依赖项。
首先,flutter_localizations是一个Flutter SDK提供的本地化库,用于本地化和国际化应用程序。通过将它添加到dependencies中,您可以在应用程序中使用与设备语言匹配的本地化资源。
而shared_preferences是一个用于持久化存储数据的Flutter插件。它允许您在应用程序内存储和检索键值对,并且这些数据将在应用程序退出后仍然保留。
第一步:在根目录lib下新建文件夹l10n,文件内容如下图所示,其中 en.dart用于存放英文文字,zh.dart用于存放中文文字,messages.dart里面的类用于获取当前语言环境下的翻译文本。
en.dart里面的代码如
zh.dart里面的代码如
messages.dart里面的代码
import 'package:flutter/material.dart';
import 'package:management_flutter/l10n/locales/en.dart' as en;
import 'package:management_flutter/l10n/locales/zh.dart' as zh;
//AppLocalizations 类用于表示应用程序的本地化资源。每个语言环境都有一个对应的 AppLocalizations 实例,用于获取该语言下的翻译文本。
class AppLocalizations {
final Locale locale;
//构造函数用于创建 AppLocalizations 实例,并传入当前的语言环境。of 方法用于从给定的上下文中获取 AppLocalizations 实例。
AppLocalizations(this.locale);
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
//_localizedValues 是一个字典,它保存着不同语言环境下的翻译文本。其中 'en' 和 'zh' 分别对应英文和中文的翻译资源,en.dart 和 zh.dart 文件分别定义了这些翻译文本。
static final Map<String, Map<String, String>> _localizedValues = {
'en': en.en,
'zh': zh.zh,
};
//operator [] 方法用于获取指定键(key)对应的翻译文本。它通过检索 _localizedValues 字典中当前语言环境的翻译文本,并返回对应的值。
String operator [](String key) {
return _localizedValues[locale.languageCode]![key]!;
}
}
//AppLocalizationsDelegate 类是一个 LocalizationsDelegate 的子类,用于提供本地化资源。
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
//isSupported 方法用于检查给定的语言环境是否受支持。在这里,我们只支持英文('en')和中文('zh')两种语言环境。
@override
bool isSupported(Locale locale) {
return ['en', 'zh'].contains(locale.languageCode);
}
//load 方法用于异步加载指定语言环境的本地化资源。在这里,我们使用 Future.delayed 方法模拟异步加载过程,并创建一个 AppLocalizations 实例。
@override
Future<AppLocalizations> load(Locale locale) async {
return AppLocalizations(locale);
}
//shouldReload 方法用于判断是否需要重新加载本地化资源。在这里,我们始终返回 false,表示不需要重新加载。
@override
bool shouldReload(AppLocalizationsDelegate old) {
return false;
}
}
第二步:入口文件main.dart修改
import 'package:flutter/material.dart';
import 'package:management_flutter/Login/LoginPage.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'l10n/messages.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
//setLocale 方法用于从应用的任何位置切换语言环境。它通过找到最近的 _MyAppState 实例,并调用其 setLocale 方法来实现切换语言功能。
static void setLocale(BuildContext context, Locale newLocale) {
_MyAppState state = context.findAncestorStateOfType<_MyAppState>()!;
state.setLocale(newLocale);
}
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Locale _locale = const Locale('en', ''); // 默认语言为英文
//_loadLocaleFromPreferences 方法从 SharedPreferences 中加载用户偏好设置的语言环境。如果存在保存的语言代码,就将其更新到 _locale 变量中。
Future<void> _loadLocaleFromPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? languageCode = prefs.getString('languageCode');
if (languageCode != null) {
setState(() {
_locale = Locale(languageCode, '');
});
}
}
//_saveLocaleToPreferences 方法用于将选择的语言环境保存到 SharedPreferences 中,以便下次启动应用时可以加载该语言环境。
Future<void> _saveLocaleToPreferences(Locale locale) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('languageCode', locale.languageCode);
}
void setLocale(Locale newLocale) {
_saveLocaleToPreferences(newLocale);
setState(() {
_locale = newLocale;
});
}
@override
void initState() {
super.initState();
_loadLocaleFromPreferences();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const LoginPage(),
localizationsDelegates: const [
AppLocalizationsDelegate(),
...GlobalMaterialLocalizations.delegates,
GlobalWidgetsLocalizations.delegate,
],
//localizationsDelegates 参数包含了用于本地化的委托,包括我们自定义的 AppLocalizationsDelegate 和 Flutter 提供的 GlobalMaterialLocalizations 和 GlobalWidgetsLocalizations。
//supportedLocales 参数定义了支持的语言环境,包括英文和中文。最后,我们将 _locale 赋给 locale 参数,设置当前的语言环境。
supportedLocales: const [
Locale('en', ''),
Locale('zh', ''),
],
locale: _locale, // 设置当前语言
);
}
}
第三步:登录页LoginPage.dart
import 'package:flutter/material.dart';
import '../l10n/messages.dart';
import '../main.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
@override
void dispose() {
_usernameController.dispose();
_passwordController.dispose();
super.dispose();
}
//_toggleLanguage 方法用于切换应用程序的语言环境。它通过获取当前的语言环境,然后根据当前语言代码切换到相应的新语言环境(英文切换为中文,中文切换为英文)
void _toggleLanguage(BuildContext context) {
var currentLocale = Localizations.localeOf(context);
var newLocale = currentLocale.languageCode == 'en'
? const Locale('zh', '')
: const Locale('en', '');
MyApp.setLocale(context, newLocale);
}
@override
Widget build(BuildContext context) {
var messages = AppLocalizations.of(context)!;
return Scaffold(
backgroundColor: const Color.fromRGBO(205, 205, 205, 1),
body: SizedBox(
height: double.infinity,
child: Column(
children: [
const HeadImageWidget(),
Expanded(
flex: 1,
child: Container(
width: double.infinity,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
padding: const EdgeInsets.all(30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
messages['loginTitle1'],
style: const TextStyle(
color: Color.fromRGBO(83, 88, 110, 1),
fontSize: 26),
),
Text(
messages['loginTitle2'],
style: const TextStyle(
color: Color.fromRGBO(205, 205, 205, 1),
fontSize: 16),
),
const SizedBox(height: 30),
TextField(
controller: _usernameController,
decoration: InputDecoration(
labelText: messages['username'],
),
),
const SizedBox(height: 16),
TextField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(
labelText: messages['password'],
),
),
const SizedBox(height: 30),
Container(
height: 48,
width: double.infinity,
decoration: BoxDecoration(
color: const Color.fromRGBO(64, 74, 124, 1),
borderRadius: BorderRadius.circular(8),
),
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
),
child: Text(
messages['login'],
),
),
),
const Spacer(),
Center(
child: GestureDetector(
onTap: () => _toggleLanguage(context),
child: Text(
messages['language'],
),
),
)
],
),
))
],
),
),
);
}
}
class HeadImageWidget extends StatelessWidget {
const HeadImageWidget({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 200,
padding: const EdgeInsets.only(top: 50),
color: const Color.fromRGBO(205, 205, 205, 1),
child: Image.asset('assets/login/fooderise_image.png'),
);
}
}