Flutter for OpenHarmony 底部选项卡与多语言适配小记:让 App 更贴心的两次小升级✨
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
一、开篇:给鸿蒙 App 加点 "贴心小细节"
哈喽~这次我给 Flutter 鸿蒙 App 做了两个超实用的小升级:底部选项卡适配和多语言国际化!就像给 App 装了个 "快捷导航栏" 和 "语言翻译器",不仅用起来更顺手,还能照顾不同语言的小伙伴,细节感直接拉满~
这次的小项目里,我搞定了两件大事:
调通了底部选项卡在鸿蒙设备上的适配,解决了切换卡顿、样式错位的小 bug
实现了超简单的多语言国际化,让 App 能说中文和英文,还能跟着系统语言自动切换
折腾完这两个功能,我也复盘了适配过程中的小坑和小技巧,分享给大家~
二、第一部分:底部选项卡适配 ------ 给 App 装个 "快捷导航栏"🎀
底部选项卡就像 App 的快捷导航栏,点一下就能在首页、消息、我的之间切换,要是适配不好,就会出现 "切换卡顿""图标错位" 的小尴尬。这次我用 Flutter 的BottomNavigationBar做了鸿蒙适配,过程踩了几个小坑,也总结了适配技巧。
踩过的小坑:
一开始直接用默认的BottomNavigationBar,在鸿蒙真机上跑的时候,发现切换页面时会有卡顿,图标和文字还会轻微错位,像被风吹歪了一样~后来才发现,是因为鸿蒙设备的渲染机制和原生平台有点不一样,复杂的选项卡配置会加重渲染压力。
适配小技巧:
用IndexedStack缓存页面,切换选项卡时不用每次都重建页面,就像给页面拍了张照片,直接拿出来用,不卡顿
减少选项卡数量,控制在 3-4 个以内,图标和文字别搞太复杂,越简单越适配
给选项卡加固定高度,避免不同鸿蒙设备上出现高度不一致的问题
底部选项卡适配代码
dart
dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '鸿蒙底部选项卡',
theme: ThemeData(primarySwatch: Colors.pink),
home: const TabPage(),
);
}
}
class TabPage extends StatefulWidget {
const TabPage({super.key});
@override
State<TabPage> createState() => _TabPageState();
}
class _TabPageState extends State<TabPage> {
int _currentIndex = 0;
// 鸿蒙优化:IndexedStack缓存页面,避免重建卡顿
final List<Widget> _pages = [
const HomePage(),
const MessagePage(),
const MinePage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
// 鸿蒙优化:减少选项卡复杂度
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.message), label: '消息'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
],
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Center(child: Text('首页'));
}
}
class MessagePage extends StatelessWidget {
const MessagePage({super.key});
@override
Widget build(BuildContext context) {
return const Center(child: Text('消息'));
}
}
class MinePage extends StatelessWidget {
const MinePage({super.key});
@override
Widget build(BuildContext context) {
return const Center(child: Text('我的'));
}
}
三、第二部分:多语言国际化 ------ 让 App 说多种语言✨
多语言国际化就像给 App 装了个小翻译器,用户切换系统语言时,App 的文字也会跟着变,不用手动改代码超方便!这次我用 Flutter 自带的Localizations实现了超简单的中英双语适配,过程也超顺利~
踩过的小坑:
一开始以为要装复杂的第三方库,后来才发现 Flutter 自带的本地化就够用了!不过一开始配置的时候,语言文件没放对位置,App 读不到翻译文本,一直显示默认文字,折腾了好久才找到问题~
实现小技巧:
用AppLocalizations自定义翻译类,把中英双语的文字写在同一个文件里,超省心
在MaterialApp里配置localizationsDelegates和supportedLocales,告诉 App 支持哪些语言
用of(context).key获取翻译文本,页面里直接调用,不用写一堆判断逻辑
多语言适配代码
dart
dart
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '鸿蒙多语言',
theme: ThemeData(primarySwatch: Colors.pink),
// 鸿蒙多语言配置
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale('zh', 'CN'),
Locale('en', 'US'),
],
home: const HomePage(),
);
}
}
// 自定义翻译类
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
// 翻译文本
static final Map<String, Map<String, String>> _localizedValues = {
'zh': {
'hello': '你好',
'home': '首页',
},
'en': {
'hello': 'Hello',
'home': 'Home',
},
};
String get hello => _localizedValues[locale.languageCode]!['hello']!;
String get home => _localizedValues[locale.languageCode]!['home']!;
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['zh', 'en'].contains(locale.languageCode);
@override
Future<AppLocalizations> load(Locale locale) async {
return AppLocalizations(locale);
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(title: Text(loc.home)),
body: Center(child: Text(loc.hello, style: const TextStyle(fontSize: 24))),
);
}
}
这是我的运行截图:


四、复盘与反思:适配路上的小收获💡
折腾完这两个功能,我也复盘了一下适配过程中的小收获:
底部选项卡适配:鸿蒙设备对渲染性能比较敏感,IndexedStack缓存页面比每次重建要丝滑很多,选项卡数量和复杂度也要控制好,越简单越稳定
多语言适配:不用一开始就依赖第三方库,Flutter 自带的本地化就足够实现基础的多语言,关键是要把配置写对,语言文件的路径和键名要对应好
通用小感悟:适配鸿蒙的时候,"简单" 比 "花哨" 更重要,复杂的配置和效果容易踩坑,先实现基础功能,再慢慢优化细节会更顺利
五、结尾:细节满满的 App 谁不爱呀~
这次的两个小升级,让我的鸿蒙 App 变得更贴心了:底部选项卡用起来丝滑顺手,多语言也能照顾不同的小伙伴~适配过程虽然踩了几个小坑,但也学到了不少实用的小技巧,超有成就感。