Flutter for OpenHarmony 微动漫App实战:关于实现
本文介绍了如何用Flutter实现一个完整的应用"关于"页面。该页面包含应用标识(Logo、名称、版本号)、应用介绍、功能特性、数据来源和联系方式等核心模块。技术实现上采用了渐变装饰、图标展示、url_launcher外部链接跳转等功能,通过Column垂直布局和SingleChildScrollView确保内容可滚动。文章详细展示了每个模块的代码实现,包括圆形容器渐变背景、e
通过网盘分享的文件:flutter1.zip
链接: https://pan.baidu.com/s/1jkLZ9mZXjNm0LgP6FTVRzw 提取码: 2t97
关于页面是App的"名片",展示应用的基本信息、功能特性、数据来源和联系方式。虽然用户不常打开,但它能传递专业感和信任感。
这篇文章会实现一个完整的关于页面,涉及渐变装饰、图标展示、url_launcher 外部链接跳转等技术点。

关于页面的内容规划
一个完整的关于页面通常包含:
应用标识:Logo、名称、版本号,让用户一眼认出这是什么App。
应用介绍:简短描述App的定位和用途。
功能特性:列出主要功能,让用户了解App能做什么。
数据来源:说明数据从哪来,增加透明度和信任感。
联系方式:提供反馈渠道,方便用户联系开发者。
页面基础结构
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class AboutScreen extends StatelessWidget {
const AboutScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('关于应用')),
body: SingleChildScrollView(
child: Column(
children: [
// 页面内容
],
),
),
);
}
}
引入 url_launcher 包,用于打开外部链接和邮件客户端。
用 SingleChildScrollView 包裹内容,当内容超出屏幕时可以滚动。Column 垂直排列各个区块。
应用标识区域
页面顶部展示App的Logo和基本信息:
Container(
padding: const EdgeInsets.all(32),
child: Column(
children: [
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [
Theme.of(context).primaryColor,
Theme.of(context).colorScheme.secondary,
],
),
),
child: const Icon(
Icons.movie,
size: 50,
color: Colors.white,
),
),
外层 Container 设置 32 像素的内边距,让内容不会贴边。
Logo 用一个圆形容器实现。BoxShape.circle 让容器变成圆形,LinearGradient 创建从主色到次色的渐变背景。
Theme.of(context).primaryColor 获取当前主题的主色,这样Logo颜色会跟随主题变化。
应用名称和版本
const SizedBox(height: 16),
const Text(
'微动漫',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'版本 1.0.0',
style: TextStyle(color: Colors.grey),
),
],
),
),
应用名称用大号粗体,版本号用灰色小字。SizedBox 控制元素之间的间距。
这个区域是视觉焦点,用户第一眼就能看到App的身份信息。
分隔线
const Divider(),
Divider 是一条水平分隔线,把标识区域和详细信息区域分开。默认样式就很好看,不需要额外配置。
应用介绍区域
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'应用介绍',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
const Text(
'微动漫是一个免费的动漫信息应用,提供最新的动漫资讯、排行榜、角色信息等内容。',
style: TextStyle(height: 1.6),
),
crossAxisAlignment: CrossAxisAlignment.start 让所有子元素左对齐。
介绍文本设置 height: 1.6 增加行高,阅读起来更舒服。内容要简洁,一两句话说清楚App是干什么的。
功能特性列表
const SizedBox(height: 24),
const Text(
'功能特性',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
_buildFeature('🎬', '浏览热门和当季动漫'),
_buildFeature('🔍', '搜索和发现新动漫'),
_buildFeature('❤️', '收藏喜欢的动漫'),
_buildFeature('👥', '查看角色信息'),
_buildFeature('📰', '阅读动漫新闻'),
_buildFeature('💬', '浏览动漫名言'),
_buildFeature('🌙', '深色/浅色主题切换'),
用 emoji 作为图标,比 Icon 更生动有趣。每个功能一行,简短明了。
功能项构建方法
Widget _buildFeature(String emoji, String text) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: [
Text(emoji, style: const TextStyle(fontSize: 18)),
const SizedBox(width: 12),
Text(text),
],
),
);
}
Row 水平排列 emoji 和文本。emoji 字号设为 18,比默认大一点,更醒目。
Padding 只设置底部间距,让每个功能项之间有适当的距离。
这个方法可以复用,添加新功能只需要调用一次。
数据来源区域
const SizedBox(height: 24),
const Text(
'数据来源',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
_buildDataSource('Jikan API', '动漫数据、角色、推荐等'),
_buildDataSource('AnimeChan', '动漫名言'),
_buildDataSource('Catboy API', '可爱图片'),
列出App使用的所有API,让用户知道数据从哪来。这是对数据提供方的尊重,也增加了透明度。
数据来源项构建方法
Widget _buildDataSource(String name, String description) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(fontWeight: FontWeight.w600),
),
const SizedBox(height: 2),
Text(
description,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
);
}
数据来源用两行展示:名称用粗体,描述用小号灰色字体。Column 垂直排列,crossAxisAlignment.start 左对齐。
和功能项不同,数据来源需要更多说明,所以用两行而不是一行。
联系方式区域
const SizedBox(height: 24),
const Text(
'联系我们',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
联系方式放在最后,用户看完前面的信息后,如果有问题可以联系开发者。
发送反馈功能
ListTile(
leading: const Icon(Icons.email),
title: const Text('发送反馈'),
onTap: () async {
final Uri emailUri = Uri(
scheme: 'mailto',
path: 'support@microanime.com',
);
if (await canLaunchUrl(emailUri)) {
await launchUrl(emailUri);
}
},
),
ListTile 是带图标的列表项,点击后打开邮件客户端。
Uri 构造邮件链接,scheme 是 mailto,path 是邮箱地址。canLaunchUrl 检查设备是否能处理这个链接,launchUrl 打开邮件客户端。
这两个方法都是异步的,需要用 async/await。
访问网站功能
ListTile(
leading: const Icon(Icons.language),
title: const Text('访问网站'),
onTap: () async {
const url = 'https://jikan.moe';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
}
},
),
点击后打开浏览器访问网站。Uri.parse 把字符串转成 Uri 对象。
Icons.language 是地球图标,通常用来表示网站链接。
url_launcher 的配置
使用 url_launcher 需要在 pubspec.yaml 添加依赖:
dependencies:
flutter:
sdk: flutter
url_launcher: ^6.1.0
在 HarmonyOS 上还需要配置权限,让App能够打开外部链接。
url_launcher 的更多用法
除了邮件和网页,url_launcher 还支持其他类型的链接:
// 打电话
final Uri phoneUri = Uri(scheme: 'tel', path: '10086');
await launchUrl(phoneUri);
// 发短信
final Uri smsUri = Uri(scheme: 'sms', path: '10086');
await launchUrl(smsUri);
// 打开地图
final Uri mapUri = Uri.parse('geo:39.9,116.4');
await launchUrl(mapUri);
不同的 scheme 对应不同的功能。tel 是电话,sms 是短信,geo 是地图坐标。
处理链接打开失败
有时候设备可能无法处理某些链接,需要给用户提示:
onTap: () async {
final Uri emailUri = Uri(
scheme: 'mailto',
path: 'support@microanime.com',
);
if (await canLaunchUrl(emailUri)) {
await launchUrl(emailUri);
} else {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('无法打开邮件客户端')),
);
}
}
},
canLaunchUrl 返回 false 时,用 SnackBar 提示用户。context.mounted 检查组件是否还在树中,避免异步操作后组件已销毁的问题。
添加版本检查功能
关于页面可以加上版本检查:
ListTile(
leading: const Icon(Icons.system_update),
title: const Text('检查更新'),
subtitle: const Text('当前版本 1.0.0'),
onTap: () {
// 检查更新逻辑
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已是最新版本')),
);
},
),
subtitle 显示当前版本号。点击后可以调用接口检查是否有新版本。
添加开源许可信息
如果App使用了开源库,可以展示许可信息:
ListTile(
leading: const Icon(Icons.description),
title: const Text('开源许可'),
onTap: () {
showLicensePage(
context: context,
applicationName: '微动漫',
applicationVersion: '1.0.0',
);
},
),
showLicensePage 是 Flutter 内置的方法,会显示所有依赖库的许可信息。这是对开源社区的尊重。
深色模式下的渐变调整
Logo 的渐变在深色模式下可能需要调整:
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Theme.of(context).primaryColor,
Theme.of(context).colorScheme.secondary,
],
),
boxShadow: [
BoxShadow(
color: Theme.of(context).primaryColor.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: const Icon(
Icons.movie,
size: 50,
color: Colors.white,
),
),
begin 和 end 控制渐变方向,从左上到右下。
boxShadow 添加阴影效果,让Logo更有立体感。阴影颜色用主色的半透明版本,和Logo颜色呼应。
添加动画效果
可以给Logo添加简单的动画:
class AboutScreen extends StatefulWidget {
const AboutScreen({super.key});
State<AboutScreen> createState() => _AboutScreenState();
}
class _AboutScreenState extends State<AboutScreen>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
}
void dispose() {
_controller.dispose();
super.dispose();
}
AnimationController 控制动画的播放。repeat(reverse: true) 让动画来回播放。
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.scale(
scale: 1.0 + _controller.value * 0.1,
child: child,
);
},
child: Container(
width: 100,
height: 100,
// Logo 内容
),
),
AnimatedBuilder 监听动画值的变化,Transform.scale 根据动画值缩放Logo。效果是Logo轻微地放大缩小,像在"呼吸"。
社交媒体链接
可以添加社交媒体链接:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.facebook),
onPressed: () => _launchUrl('https://facebook.com'),
),
IconButton(
icon: const Icon(Icons.telegram),
onPressed: () => _launchUrl('https://t.me/channel'),
),
IconButton(
icon: const Icon(Icons.discord),
onPressed: () => _launchUrl('https://discord.gg/invite'),
),
],
),
Row 水平排列图标按钮,mainAxisAlignment.center 居中显示。
Future<void> _launchUrl(String url) async {
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
}
}
把打开链接的逻辑抽成方法,避免重复代码。
复制邮箱地址
有些用户可能想复制邮箱而不是直接发邮件:
ListTile(
leading: const Icon(Icons.email),
title: const Text('发送反馈'),
subtitle: const Text('support@microanime.com'),
onTap: () async {
// 打开邮件客户端
},
onLongPress: () {
Clipboard.setData(
const ClipboardData(text: 'support@microanime.com'),
);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('邮箱已复制')),
);
},
),
onLongPress 处理长按事件,Clipboard.setData 复制文本到剪贴板。需要引入 package:flutter/services.dart。
页面跳转
关于页面通常从设置或个人中心进入:
ListTile(
leading: const Icon(Icons.info_outline),
title: const Text('关于应用'),
trailing: const Icon(Icons.chevron_right),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const AboutScreen()),
);
},
),
Icons.info_outline 是信息图标,常用于关于页面的入口。
小结
关于页面涉及的技术点:LinearGradient 渐变、BoxDecoration 装饰、url_launcher 外部链接、ListTile 列表项、SingleChildScrollView 滚动、Divider 分隔线。
内容组织上,从上到下依次是:应用标识、应用介绍、功能特性、数据来源、联系方式。层次分明,信息完整。
关于页面虽然不是核心功能,但它展示了App的专业度。花点心思把它做好,用户会感受到开发者的用心。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)