diff --git a/lib/common/constant.dart b/lib/common/constant.dart index 6218fef..e1d4ea4 100644 --- a/lib/common/constant.dart +++ b/lib/common/constant.dart @@ -63,7 +63,7 @@ const defaultTestUrl = 'https://www.gstatic.com/generate_204'; final commonFilter = ImageFilter.blur( sigmaX: 5, sigmaY: 5, - tileMode: TileMode.mirror, + tileMode: TileMode.clamp, ); const listEquality = ListEquality(); diff --git a/lib/views/profiles/overwrite/custom_proxies.dart b/lib/views/profiles/overwrite/custom_proxies.dart index bda275c..3f40d32 100644 --- a/lib/views/profiles/overwrite/custom_proxies.dart +++ b/lib/views/profiles/overwrite/custom_proxies.dart @@ -159,6 +159,9 @@ class _EditProxyGroupNestedSheet extends StatelessWidget { child: PagedSheet( decoration: MaterialSheetDecoration( size: SheetSize.stretch, + color: sheetProvider.type == SheetType.bottomSheet + ? context.colorScheme.surfaceContainerLow + : context.colorScheme.surface, borderRadius: sheetProvider.type == SheetType.bottomSheet ? BorderRadius.vertical(top: Radius.circular(28)) : BorderRadius.zero, @@ -410,7 +413,7 @@ class _EditProxyGroupViewState extends ConsumerState<_EditProxyGroupView> { final isBottomSheet = SheetProvider.of(context)?.type == SheetType.bottomSheet; return AdaptiveSheetScaffold( - bottomSheetBackdrop: true, + sheetTransparentToolBar: true, actions: [IconButtonData(icon: Icons.check, onPressed: () {})], body: SizedBox( height: isBottomSheet @@ -648,11 +651,11 @@ class _EditProxiesViewState extends ConsumerState<_EditProxiesView> { : double.maxFinite, child: AdaptiveSheetScaffold( title: '编辑代理', - bottomSheetBackdrop: true, + sheetTransparentToolBar: true, body: CustomScrollView( slivers: [ SliverToBoxAdapter( - child: SizedBox(height: context.sheetTopPadding), + child: SizedBox(height: context.sheetTopPadding + 8), ), SliverPadding( padding: EdgeInsets.symmetric(horizontal: 16), @@ -761,7 +764,7 @@ class _AddProxiesView extends ConsumerWidget { ? appController.viewSize.height * 0.80 : double.maxFinite, child: AdaptiveSheetScaffold( - bottomSheetBackdrop: true, + sheetTransparentToolBar: true, title: '添加代理', body: CustomScrollView( slivers: [ diff --git a/lib/views/profiles/profiles.dart b/lib/views/profiles/profiles.dart index 9ef6858..1e3eab4 100644 --- a/lib/views/profiles/profiles.dart +++ b/lib/views/profiles/profiles.dart @@ -463,7 +463,7 @@ class _ReorderableProfilesSheetState extends State { @override Widget build(BuildContext context) { return AdaptiveSheetScaffold( - bottomSheetBackdrop: true, + sheetTransparentToolBar: true, actions: [IconButtonData(icon: Icons.check, onPressed: _handleSave)], body: Padding( padding: EdgeInsets.only(bottom: 32), diff --git a/lib/widgets/sheet.dart b/lib/widgets/sheet.dart index cd6ca80..c967413 100644 --- a/lib/widgets/sheet.dart +++ b/lib/widgets/sheet.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/controller.dart'; import 'package:fl_clash/models/common.dart'; @@ -110,14 +112,14 @@ Future showExtend( class AdaptiveSheetScaffold extends StatefulWidget { final Widget body; final String title; - final bool bottomSheetBackdrop; + final bool sheetTransparentToolBar; final List actions; const AdaptiveSheetScaffold({ super.key, required this.body, required this.title, - this.bottomSheetBackdrop = false, + this.sheetTransparentToolBar = false, this.actions = const [], }); @@ -126,6 +128,8 @@ class AdaptiveSheetScaffold extends StatefulWidget { } class _AdaptiveSheetScaffoldState extends State { + final _isScrolledController = ValueNotifier(false); + IconData get backIconData { if (kIsWeb) { return Icons.arrow_back; @@ -142,14 +146,22 @@ class _AdaptiveSheetScaffoldState extends State { } } + @override + void dispose() { + _isScrolledController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - final backgroundColor = context.colorScheme.surface; final sheetProvider = SheetProvider.of(context); final nestedNavigatorPopCallback = sheetProvider?.nestedNavigatorPopCallback; final ModalRoute? route = ModalRoute.of(context); final type = sheetProvider?.type ?? SheetType.page; + final backgroundColor = type == SheetType.bottomSheet + ? context.colorScheme.surfaceContainerLow + : context.colorScheme.surface; final useCloseIcon = type != SheetType.page && (nestedNavigatorPopCallback != null && @@ -204,10 +216,7 @@ class _AdaptiveSheetScaffoldState extends State { final suffixPop = type != SheetType.page && actions.isEmpty && useCloseIcon; final appBar = AppBar( - backgroundColor: - type == SheetType.bottomSheet && widget.bottomSheetBackdrop == true - ? backgroundColor.opacity80 - : backgroundColor, + backgroundColor: backgroundColor, forceMaterialTransparency: type == SheetType.bottomSheet ? true : false, leading: suffixPop ? null : popButton, automaticallyImplyLeading: type == SheetType.page ? true : false, @@ -244,38 +253,63 @@ class _AdaptiveSheetScaffoldState extends State { ); return ScrollConfiguration( behavior: HiddenBarScrollBehavior(), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (!widget.bottomSheetBackdrop) ...[ - sheetAppBar, - Flexible(child: widget.body), - ] else ...[ - Flexible( - child: Stack( - children: [ - widget.body, - Positioned( - top: 0, - left: 0, - right: 0, - child: ClipRRect( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), - ), - child: BackdropFilter( - filter: commonFilter, + child: ClipRRect( + borderRadius: BorderRadius.vertical(top: Radius.circular(28)), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (!widget.sheetTransparentToolBar) ...[ + sheetAppBar, + Flexible(child: widget.body), + ] else ...[ + Flexible( + child: Stack( + children: [ + NotificationListener( + child: widget.body, + onNotification: (notification) { + if (notification is ScrollUpdateNotification) { + final pixels = notification.metrics.pixels; + _isScrolledController.value = pixels > 6; + } + return false; + }, + ), + Positioned( + top: 0, + left: 0, + right: 0, + child: ValueListenableBuilder( + valueListenable: _isScrolledController, + builder: (_, isScrolled, child) { + return ClipRRect( + borderRadius: BorderRadius.vertical( + top: Radius.circular(28), + ), + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 15.0, + sigmaY: 15.0, + ), + child: ColoredBox( + color: isScrolled + ? backgroundColor.opacity60 + : backgroundColor, + child: child!, + ), + ), + ); + }, child: sheetAppBar, ), ), - ), - ], + ], + ), ), - ), + ], + SizedBox(height: MediaQuery.of(context).viewPadding.bottom), ], - SizedBox(height: MediaQuery.of(context).viewPadding.bottom), - ], + ), ), ); }