feat(flutter): 统一二级页头并恢复新剧暖色
This commit is contained in:
1 parent
7b2970d5c5
commit
1c6c92170d
26 files changed
+492
-427
No files matched your search
@@ -3,6 +3,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/app_colors.dart';
|
||||
import 'subpage_header.dart';
|
||||
|
||||
/// 二级页面通用骨架:返回栏 + 标题/副标题 + 可滚动内容,无底部导航。
|
||||
class PlainPageScaffold extends StatelessWidget {
|
||||
@@ -30,47 +31,11 @@ class PlainPageScaffold extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(6, 4, 14, 0),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
key: backKey,
|
||||
tooltip: MaterialLocalizations.of(
|
||||
context,
|
||||
).backButtonTooltip,
|
||||
onPressed: () => Navigator.of(context).maybePop(),
|
||||
icon: const Icon(
|
||||
Icons.chevron_left_rounded,
|
||||
color: AppColors.onSurface,
|
||||
size: 26,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
AppSubpageHeader(
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
backKey: backKey,
|
||||
),
|
||||
if (subtitle != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: Text(
|
||||
subtitle!,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: AppColors.muted, fontSize: 12),
|
||||
),
|
||||
),
|
||||
Expanded(child: child),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/app_colors.dart';
|
||||
|
||||
const double _height = 52;
|
||||
const double _heightWithSubtitle = 64;
|
||||
const double _horizontal = 14;
|
||||
const double _backSize = 36;
|
||||
const double _backGap = 12;
|
||||
const double _titleFontSize = 18;
|
||||
const double _subtitleFontSize = 12;
|
||||
const double _actionGap = 8;
|
||||
const double _iconSize = 20;
|
||||
|
||||
/// 二级页面统一返回按钮,浅色页使用 card 圆底,深色页使用透明底。
|
||||
class AppSubpageBackButton extends StatelessWidget {
|
||||
const AppSubpageBackButton({
|
||||
super.key,
|
||||
required this.backKey,
|
||||
this.dark = false,
|
||||
this.onBack,
|
||||
});
|
||||
|
||||
final Key backKey;
|
||||
final bool dark;
|
||||
final VoidCallback? onBack;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
key: backKey,
|
||||
width: _backSize,
|
||||
height: _backSize,
|
||||
child: Tooltip(
|
||||
message: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
child: Material(
|
||||
color: dark ? Colors.transparent : AppColors.card,
|
||||
shape: const CircleBorder(),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: onBack ?? () => Navigator.of(context).maybePop(),
|
||||
child: Icon(
|
||||
Icons.chevron_left_rounded,
|
||||
color: dark ? Colors.white : AppColors.onSurface,
|
||||
size: _iconSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 二级页面统一页头:返回按钮、左对齐标题、可选副标题与右侧操作。
|
||||
class AppSubpageHeader extends StatelessWidget {
|
||||
const AppSubpageHeader({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.backKey,
|
||||
this.subtitle,
|
||||
this.actions,
|
||||
this.onBack,
|
||||
this.dark = false,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final Key backKey;
|
||||
final String? subtitle;
|
||||
final Widget? actions;
|
||||
final VoidCallback? onBack;
|
||||
final bool dark;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final foreground = dark ? Colors.white : AppColors.onSurface;
|
||||
final secondary = dark ? Colors.white70 : AppColors.muted;
|
||||
return SizedBox(
|
||||
key: const Key('subpage-header'),
|
||||
height: subtitle == null ? _height : _heightWithSubtitle,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: _horizontal),
|
||||
child: Row(
|
||||
children: [
|
||||
AppSubpageBackButton(backKey: backKey, dark: dark, onBack: onBack),
|
||||
const SizedBox(width: _backGap),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
key: const Key('subpage-title'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: foreground,
|
||||
fontSize: _titleFontSize,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle!,
|
||||
key: const Key('subpage-subtitle'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: secondary,
|
||||
fontSize: _subtitleFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (actions != null) ...[
|
||||
const SizedBox(width: _actionGap),
|
||||
actions!,
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user