feat(flutter): 应用浅色暖橙视觉主题
This commit is contained in:
1 parent
0d2367431d
commit
634b63e16c
56 files changed
+941
-409
No files matched your search
@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import '../theme/app_dimens.dart';
|
||||
|
||||
/// One destination rendered by [AppBottomNav].
|
||||
/// 底部导航普通目的地。
|
||||
class AppBottomNavItem {
|
||||
const AppBottomNavItem({
|
||||
required this.tabKey,
|
||||
@@ -26,41 +26,69 @@ class AppBottomNavItem {
|
||||
final bool selected;
|
||||
}
|
||||
|
||||
/// Shared bottom navigation used by the root shell and standalone tabs.
|
||||
/// 底部导航中央操作按钮。
|
||||
class AppBottomNavCenterAction {
|
||||
const AppBottomNavCenterAction({
|
||||
required this.label,
|
||||
required this.onTap,
|
||||
this.key = const Key('nav-center-action'),
|
||||
});
|
||||
|
||||
final Key key;
|
||||
final String label;
|
||||
final VoidCallback onTap;
|
||||
}
|
||||
|
||||
/// 全局五槽底部导航。
|
||||
class AppBottomNav extends StatelessWidget {
|
||||
const AppBottomNav({
|
||||
super.key,
|
||||
required this.items,
|
||||
this.centerAction,
|
||||
this.backgroundColor = AppColors.bar,
|
||||
this.barKey,
|
||||
});
|
||||
|
||||
final List<AppBottomNavItem> items;
|
||||
final AppBottomNavCenterAction? centerAction;
|
||||
final Color backgroundColor;
|
||||
final Key? barKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Container(
|
||||
key: barKey,
|
||||
height: AppDimens.navHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor.withValues(alpha: 0.95),
|
||||
border: const Border(
|
||||
top: BorderSide(color: AppColors.outlineVariantDark),
|
||||
Widget build(BuildContext context) {
|
||||
final action = centerAction;
|
||||
return ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Container(
|
||||
key: barKey,
|
||||
height: AppDimens.navHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor.withValues(alpha: 0.95),
|
||||
border: const Border(top: BorderSide(color: AppColors.border)),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [for (final item in items) _NavDestination(item: item)],
|
||||
child: action == null
|
||||
? Row(
|
||||
children: [
|
||||
for (final item in items) _NavDestination(item: item),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: [
|
||||
for (final item in items.take(2))
|
||||
_NavDestination(item: item),
|
||||
Expanded(child: _CenterDestination(action: action)),
|
||||
for (final item in items.skip(2))
|
||||
_NavDestination(item: item),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NavDestination extends StatelessWidget {
|
||||
@@ -78,7 +106,7 @@ class _NavDestination extends StatelessWidget {
|
||||
key: item.tabKey,
|
||||
onTap: item.onTap,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minHeight: 48),
|
||||
constraints: const BoxConstraints(minHeight: AppDimens.navHeight),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@@ -91,7 +119,7 @@ class _NavDestination extends StatelessWidget {
|
||||
size: AppDimens.navIcon,
|
||||
color: item.selected
|
||||
? AppColors.blue
|
||||
: Colors.white.withValues(alpha: 0.45),
|
||||
: AppColors.navUnselected,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
@@ -104,7 +132,7 @@ class _NavDestination extends StatelessWidget {
|
||||
fontWeight: item.selected ? FontWeight.w700 : FontWeight.w500,
|
||||
color: item.selected
|
||||
? AppColors.blue
|
||||
: Colors.white.withValues(alpha: 0.45),
|
||||
: AppColors.navUnselected,
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
@@ -115,3 +143,53 @@ class _NavDestination extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _CenterDestination extends StatelessWidget {
|
||||
const _CenterDestination({required this.action});
|
||||
|
||||
final AppBottomNavCenterAction action;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: action.label,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
shape: const CircleBorder(),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Ink(
|
||||
width: AppDimens.navCenter,
|
||||
height: AppDimens.navCenter,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [AppColors.navCenterStart, AppColors.navCenterEnd],
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.navCenterShadow,
|
||||
blurRadius: 14,
|
||||
offset: Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: InkWell(
|
||||
key: action.key,
|
||||
customBorder: const CircleBorder(),
|
||||
onTap: action.onTap,
|
||||
child: const Icon(
|
||||
Icons.add_rounded,
|
||||
color: AppColors.onPrimary,
|
||||
size: AppDimens.navCenterIcon,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import '../theme/app_dimens.dart';
|
||||
|
||||
/// Dark glass surface used by the home info card and floating controls.
|
||||
/// 首页信息卡与浮层控件使用的浅色玻璃面板。
|
||||
class GlassPanel extends StatelessWidget {
|
||||
const GlassPanel({
|
||||
super.key,
|
||||
@@ -38,7 +38,7 @@ class GlassPanel extends StatelessWidget {
|
||||
const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0x24FFFFFF), Color(0x0DFFFFFF)],
|
||||
colors: [Color(0xE6FFFFFF), Color(0xB3FFFDFB)],
|
||||
),
|
||||
),
|
||||
child: Padding(padding: padding ?? EdgeInsets.zero, child: child),
|
||||
|
||||
Reference in new issue
Block a user