opt persist header

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-02-03 17:25:33 +08:00
parent 2596859778
commit 50561b8dc1
5 changed files with 118 additions and 75 deletions

View File

@@ -1,18 +1,15 @@
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show RenderProxyBox;
class CustomSliverPersistentHeaderDelegate
extends SliverPersistentHeaderDelegate {
const CustomSliverPersistentHeaderDelegate({
required this.child,
required this.bgColor,
double extent = 45,
this.bgColor,
this.extent = 45,
this.needRebuild = false,
}) : _minExtent = extent,
_maxExtent = extent;
final double _minExtent;
final double _maxExtent;
});
final double extent;
final Widget child;
final Color? bgColor;
final bool needRebuild;
@@ -26,31 +23,16 @@ class CustomSliverPersistentHeaderDelegate
//创建child子组件
//shrinkOffsetchild偏移值minExtent~maxExtent
//overlapsContentSliverPersistentHeader覆盖其他子组件返回true否则返回false
return bgColor != null
? DecoratedBox(
decoration: BoxDecoration(
color: bgColor,
boxShadow: Platform.isIOS
? null
: [
BoxShadow(
color: bgColor!,
offset: const Offset(0, -1),
),
],
),
child: child,
)
: child;
return _DecoratedBox(color: bgColor, child: child);
}
//SliverPersistentHeader最大高度
@override
double get maxExtent => _maxExtent;
double get maxExtent => extent;
//SliverPersistentHeader最小高度
@override
double get minExtent => _minExtent;
double get minExtent => extent;
@override
bool shouldRebuild(CustomSliverPersistentHeaderDelegate oldDelegate) {
@@ -58,3 +40,62 @@ class CustomSliverPersistentHeaderDelegate
(needRebuild && oldDelegate.child != child);
}
}
class _DecoratedBox extends SingleChildRenderObjectWidget {
const _DecoratedBox({
this.color,
super.child,
});
final Color? color;
@override
RenderObject createRenderObject(BuildContext context) {
return _RenderDecoratedBox(color: color);
}
@override
void updateRenderObject(
BuildContext context,
_RenderDecoratedBox renderObject,
) {
renderObject.color = color;
}
}
class _RenderDecoratedBox extends RenderProxyBox {
_RenderDecoratedBox({
Color? color,
}) : _color = color;
Color? _color;
Color? get color => _color;
set color(Color? value) {
if (_color == value) return;
_color = value;
markNeedsPaint();
}
@override
void paint(PaintingContext context, Offset offset) {
if (_color case final color?) {
final size = this.size;
context.canvas.drawRect(
Rect.fromLTWH(
offset.dx,
offset.dy - 2,
size.width,
size.height + 2,
),
Paint()..color = color,
);
}
super.paint(context, offset);
}
@override
bool hitTestSelf(Offset position) => true;
@override
bool get isRepaintBoundary => true;
}

View File

@@ -81,13 +81,14 @@ class _DynTopicPageState extends State<DynTopicPage> with DynMixin {
return SliverPersistentHeader(
pinned: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 30,
extent: 36,
needRebuild: true,
bgColor: theme.colorScheme.surface,
child: Container(
height: 30,
height: 36,
padding: EdgeInsets.only(
left: 12 + padding.left,
top: 6,
bottom: 6,
),
child: Builder(
@@ -101,16 +102,14 @@ class _DynTopicPageState extends State<DynTopicPage> with DynMixin {
minHeight: 24,
),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
borderRadius: const BorderRadius.all(
Radius.circular(25),
),
borderRadius: const .all(.circular(25)),
onPressed: (index) {
_controller.onSort(allSortBy[index].sortBy!);
(context as Element).markNeedsBuild();
},
isSelected: allSortBy.map((e) {
return e.sortBy == _controller.sortBy;
}).toList(),
isSelected: allSortBy
.map((e) => e.sortBy == _controller.sortBy)
.toList(),
children: allSortBy.map((e) {
return Text(
e.sortName!,

View File

@@ -107,7 +107,6 @@ class _LiveDmBlockPageState extends State<LiveDmBlockPage> {
delegate: CustomSliverPersistentHeaderDelegate(
extent: 48,
child: tabBar,
bgColor: null,
),
),
),

View File

@@ -160,7 +160,6 @@ class _MemberFavoriteState extends State<MemberFavorite>
},
),
),
bgColor: null,
),
),
Obx(() {

View File

@@ -6,7 +6,6 @@ import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPlus/common/widgets/dialog/report.dart';
import 'package:PiliPlus/common/widgets/marquee.dart';
import 'package:PiliPlus/http/danmaku.dart';
@@ -1580,26 +1579,21 @@ class HeaderControlState extends State<HeaderControl>
if (ctr == null) return;
showBottomSheet((context, setState) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.all(12),
child: Material(
clipBehavior: Clip.hardEdge,
return Container(
margin: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: CustomSliverPersistentHeaderDelegate(
child: Container(
),
child: Column(
children: [
Container(
height: 45,
padding: const EdgeInsets.symmetric(horizontal: 14),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: theme.colorScheme.outline.withValues(
alpha: 0.1,
),
color: theme.colorScheme.outline.withValues(alpha: 0.1),
),
),
),
@@ -1614,16 +1608,27 @@ class HeaderControlState extends State<HeaderControl>
],
),
),
bgColor: theme.colorScheme.surface,
),
Expanded(
child: Material(
type: .transparency,
clipBehavior: .hardEdge,
borderRadius: const BorderRadius.vertical(
bottom: Radius.circular(12),
),
child: CustomScrollView(
slivers: [
?_buildDanmakuList(ctr.staticDanmaku.nonNulls.toList()),
?_buildDanmakuList(ctr.scrollDanmaku.expand((e) => e).toList()),
?_buildDanmakuList(
ctr.scrollDanmaku.expand((e) => e).toList(),
),
?_buildDanmakuList(ctr.specialDanmaku.toList()),
const SliverToBoxAdapter(child: SizedBox(height: 12)),
],
),
),
),
],
),
);
});
}