Files
ReelShort/lib/core/widgets/subpage_header.dart
T

188 lines
5.2 KiB
Dart

// 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 = 40;
const double _backGap = 12;
const double _titleFontSize = 18;
const double _subtitleFontSize = 12;
const double _actionGap = 8;
const double _iconSize = 22;
const double _iconWeight = 600;
const double _shadowBlur = 8;
/// 二级页面统一圆形操作按钮,返回、分享和更多共用同一尺寸与表面样式。
class AppSubpageCircleButton extends StatelessWidget {
const AppSubpageCircleButton({
super.key,
required this.buttonKey,
required this.tooltip,
required this.icon,
required this.onPressed,
this.dark = false,
});
final Key buttonKey;
final String tooltip;
final IconData icon;
final VoidCallback onPressed;
final bool dark;
@override
Widget build(BuildContext context) {
return SizedBox(
key: buttonKey,
width: _backSize,
height: _backSize,
child: Tooltip(
message: tooltip,
child: DecoratedBox(
key: const Key('subpage-back-shadow'),
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: dark
? const [
BoxShadow(
color: AppColors.shadowSoft,
blurRadius: _shadowBlur,
),
]
: const [],
),
child: Material(
color: dark ? AppColors.headerScrim : AppColors.transparent,
shape: const CircleBorder(),
clipBehavior: Clip.antiAlias,
child: InkWell(
customBorder: const CircleBorder(),
onTap: onPressed,
child: Center(
child: Icon(
icon,
color: dark ? AppColors.onSurface : AppColors.textPrimary,
size: _iconSize,
weight: _iconWeight,
),
),
),
),
),
),
);
}
}
/// 二级页面统一返回按钮,普通页透明,沉浸页使用半透明黑底。
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 AppSubpageCircleButton(
buttonKey: backKey,
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
icon: Icons.chevron_left_rounded,
dark: dark,
onPressed: onBack ?? () => Navigator.of(context).maybePop(),
);
}
}
/// 二级页面统一页头:返回按钮、左对齐标题、可选副标题与右侧操作。
class AppSubpageHeader extends StatelessWidget {
const AppSubpageHeader({
super.key,
required this.title,
required this.backKey,
this.subtitle,
this.actions,
this.onBack,
this.dark = false,
this.showBack = true,
});
final String title;
final Key backKey;
final String? subtitle;
final Widget? actions;
final VoidCallback? onBack;
final bool dark;
final bool showBack;
@override
Widget build(BuildContext context) {
final foreground = AppColors.textPrimary;
final secondary = AppColors.textSecondary;
return SizedBox(
key: const Key('subpage-header'),
height: subtitle == null ? _height : _heightWithSubtitle,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: _horizontal),
child: Row(
children: [
if (showBack) ...[
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!,
],
],
),
),
);
}
}