Flutter for OpenHarmony Web开发助手App实战:时间戳转换
选择合适的降落点是游戏的第一步。不同的降落点有不同的资源和风险。今天我们来实现一个降落点推荐系统。
·

时间戳是Unix时间的表示方式,在Web开发中经常用到。今天我们实现一个时间戳转换工具,让时间戳和日期时间之间的转换变得简单。
拆分实现思路
这个页面来自真实的助手工具项目,我把关键路径拆成小片段,方便理解和复用。每段代码后面都会补充具体的使用场景和注意点。
0) 依赖与入口挂载
import 'package:intl/intl.dart';
import 'package:get/get.dart';
说明:
intl负责日期格式化,实际项目里一般统一在一个工具类中封装,但页面内部直接用也足够清晰。get用来弹出提示,轻量、少样板,适合工具类页面的反馈。
// 路由入口
GetPage(
name: '/timestamp',
page: () => const TimestampConverterPage(),
),
说明:
- 时间戳工具一般是“工具箱”里的子页面,路由注册是第一步。
- 真实项目里不会把页面挂在首页,独立路由能保持结构清爽。
1) 页面入口与状态
class TimestampConverterPage extends StatefulWidget {
const TimestampConverterPage({Key? key}) : super(key: key);
State<TimestampConverterPage> createState() => _TimestampConverterPageState();
}
class _TimestampConverterPageState extends State<TimestampConverterPage> {
final TextEditingController _timestampController = TextEditingController();
DateTime _selectedDateTime = DateTime.now();
bool _isMilliseconds = true;
}
说明:
TextEditingController负责时间戳输入的读写,便于按钮点击时拿到最新值。_selectedDateTime作为页面统一的时间状态,后面的结果面板都从这里读。_isMilliseconds用来区分秒/毫秒,这个开关决定解析逻辑。
2) 初始化时填充当前时间戳
void initState() {
super.initState();
_updateTimestamp();
}
说明:
- 进入页面先填一次时间戳,避免空白态。
- 真实项目里用户更希望“打开即用”,而不是先输入。
3) 当前时间卡片
Card(
color: Colors.blue[50],
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
Text('当前时间', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
SizedBox(height: 8.h),
Text(
DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold, color: Colors.blue[900]),
),
SizedBox(height: 8.h),
Text(
'时间戳: ${DateTime.now().millisecondsSinceEpoch}',
style: TextStyle(fontSize: 14.sp, fontFamily: 'monospace'),
),
],
),
),
)
说明:
- 这里展示“当前时间 + 当前时间戳”,用户对比最直观。
DateFormat来自intl,项目里一般会全局封装,但本例直接用更清晰。
4) 时间戳输入与复制
TextField(
controller: _timestampController,
keyboardType: TextInputType.number,
style: TextStyle(fontSize: 18.sp, fontFamily: 'monospace'),
decoration: InputDecoration(
hintText: '输入时间戳...',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.r)),
suffixIcon: IconButton(
icon: const Icon(Icons.copy),
onPressed: () => _copy(_timestampController.text),
),
),
)
说明:
- 输入框启用数字键盘,避免用户输入非数字。
- 右侧复制按钮是常见交互,小工具类应用很吃这个细节。
5) 毫秒/秒切换 + 转换按钮
Row(
children: [
Checkbox(
value: _isMilliseconds,
onChanged: (v) => setState(() => _isMilliseconds = v ?? true),
),
const Text('毫秒'),
SizedBox(width: 16.w),
ElevatedButton(
onPressed: _parseTimestamp,
child: const Text('转换为日期'),
),
],
)
说明:
- 真实项目里不少后端返回的是秒级时间戳,这个切换很必要。
- 点击按钮走解析逻辑,避免输入框变化就频繁解析。
6) 时间戳解析逻辑
void _parseTimestamp() {
final timestamp = int.tryParse(_timestampController.text);
if (timestamp == null) {
Get.snackbar('错误', '请输入有效的时间戳', snackPosition: SnackPosition.BOTTOM);
return;
}
setState(() {
_selectedDateTime = DateTime.fromMillisecondsSinceEpoch(
_isMilliseconds ? timestamp : timestamp * 1000,
);
});
}
说明:
int.tryParse可以避免异常,输入不合法直接提示。- 关键点是秒转毫秒:
timestamp * 1000,不少人踩过这个坑。
7) 日期与时间选择
ListTile(
leading: const Icon(Icons.calendar_today),
title: Text(DateFormat('yyyy-MM-dd').format(_selectedDateTime)),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: _pickDate,
),
说明:
- 用
ListTile做入口,保持一致的列表样式。 - 日期和时间拆开选择,用户操作成本更低。
Future<void> _pickDate() async {
final date = await showDatePicker(
context: context,
initialDate: _selectedDateTime,
firstDate: DateTime(1970),
lastDate: DateTime(2100),
);
if (date != null) {
setState(() {
_selectedDateTime = DateTime(
date.year,
date.month,
date.day,
_selectedDateTime.hour,
_selectedDateTime.minute,
_selectedDateTime.second,
);
_updateTimestamp();
});
}
}
说明:
- 选择日期后保留原来的时分秒,体验更连贯。
- 调用
_updateTimestamp()保证输入框的时间戳同步更新。
Future<void> _pickTime() async {
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(_selectedDateTime),
);
if (time != null) {
setState(() {
_selectedDateTime = DateTime(
_selectedDateTime.year,
_selectedDateTime.month,
_selectedDateTime.day,
time.hour,
time.minute,
);
_updateTimestamp();
});
}
}
说明:
- 时间选择和日期选择拆开,减少用户一次性操作压力。
- 更新后统一调用
_updateTimestamp(),保证结果区和输入框一致。
8) 结果展示行
Widget _buildResultRow(String label, String value) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 4.h),
child: Row(
children: [
SizedBox(
width: 100.w,
child: Text(label, style: TextStyle(fontSize: 13.sp, color: Colors.grey[700])),
),
Expanded(
child: Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(value, style: TextStyle(fontSize: 13.sp, fontFamily: 'monospace')),
),
IconButton(
icon: const Icon(Icons.copy, size: 18),
onPressed: () => _copy(value),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
],
),
),
),
],
),
);
}
说明:
- 这段是复用组件,真实页面里会被多次调用。
value采用等宽字体,方便用户比对时间戳长度。
9) 复制反馈
void _copy(String text) {
Clipboard.setData(ClipboardData(text: text));
Get.snackbar('成功', '已复制', snackPosition: SnackPosition.BOTTOM, duration: const Duration(seconds: 2));
}
说明:
- 轻量提示足够,避免弹窗打断流程。
Get.snackbar在 OpenHarmony Web 的小工具类页面里非常实用。
10) 时间戳同步
void _updateTimestamp() {
setState(() {
_timestampController.text = _selectedDateTime.millisecondsSinceEpoch.toString();
});
}
说明:
- 用户从“日期→时间戳”路径时,输入框的值必须跟着更新。
- 这里用
setState保证结果面板也能一起刷新。
小结
本工具的关键点在于:统一使用 _selectedDateTime 做状态来源、解析时处理秒/毫秒差异、并且保持输入框与选择器的同步。这样即使页面看起来简单,也能在真实项目中稳定运行。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)