diff --git a/lib/common/widgets/dynamic_sliver_appbar_medium.dart b/lib/common/widgets/dynamic_sliver_appbar_medium.dart index 18b59c946..c29859ff6 100644 --- a/lib/common/widgets/dynamic_sliver_appbar_medium.dart +++ b/lib/common/widgets/dynamic_sliver_appbar_medium.dart @@ -43,10 +43,10 @@ class DynamicSliverAppBarMedium extends StatefulWidget { this.forceMaterialTransparency = false, this.clipBehavior, this.appBarClipper, - this.afterCalc, + this.onPerformLayout, }); - final ValueChanged? afterCalc; + final ValueChanged? onPerformLayout; final Widget? flexibleSpace; final Widget? leading; final bool automaticallyImplyLeading; @@ -93,7 +93,6 @@ class DynamicSliverAppBarMedium extends StatefulWidget { } class _DynamicSliverAppBarMediumState extends State { - final GlobalKey _key = GlobalKey(); double? _height; double? _width; late double _topPadding; @@ -112,18 +111,17 @@ class _DynamicSliverAppBarMediumState extends State { @override Widget build(BuildContext context) { if (_height == null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _height = - (_key.currentContext!.findRenderObject() as RenderBox).size.height; - widget.afterCalc?.call(_height!); - setState(() {}); - }); return SliverToBoxAdapter( child: OnlyLayoutWidget( + onPerformLayout: (Size size) { + if (!mounted) return; + _height = size.height; + widget.onPerformLayout?.call(_height!); + setState(() {}); + }, child: UnconstrainedBox( alignment: Alignment.topLeft, child: SizedBox( - key: _key, width: _width, child: widget.flexibleSpace, ), diff --git a/lib/common/widgets/only_layout_widget.dart b/lib/common/widgets/only_layout_widget.dart index 91acee038..2dcc67074 100644 --- a/lib/common/widgets/only_layout_widget.dart +++ b/lib/common/widgets/only_layout_widget.dart @@ -1,17 +1,42 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart' show RenderProxyBox; +import 'package:flutter/scheduler.dart'; + +typedef LayoutCallback = void Function(Size size); class OnlyLayoutWidget extends SingleChildRenderObjectWidget { const OnlyLayoutWidget({ super.key, super.child, + required this.onPerformLayout, }); + final LayoutCallback onPerformLayout; + @override - RenderObject createRenderObject(BuildContext context) => Layout(); + RenderObject createRenderObject(BuildContext context) => + Layout(onPerformLayout: onPerformLayout); + + @override + void updateRenderObject(BuildContext context, Layout renderObject) { + super.updateRenderObject(context, renderObject); + renderObject.onPerformLayout = onPerformLayout; + } } class Layout extends RenderProxyBox { + Layout({required this.onPerformLayout}); + + LayoutCallback onPerformLayout; + + @override + void performLayout() { + super.performLayout(); + SchedulerBinding.instance.addPostFrameCallback((_) { + onPerformLayout(size); + }); + } + @override void paint(PaintingContext context, Offset offset) {} } diff --git a/lib/common/widgets/self_sized_horizontal_list.dart b/lib/common/widgets/self_sized_horizontal_list.dart index 3409d6d28..dea354ea8 100644 --- a/lib/common/widgets/self_sized_horizontal_list.dart +++ b/lib/common/widgets/self_sized_horizontal_list.dart @@ -23,22 +23,17 @@ class SelfSizedHorizontalList extends StatefulWidget { } class _SelfSizedHorizontalListState extends State { - final _key = GlobalKey(); double? _height; @override Widget build(BuildContext context) { if (_height == null) { - WidgetsBinding.instance.addPostFrameCallback( - (_) { - _height = (_key.currentContext!.findRenderObject() as RenderBox) - .size - .height; + return OnlyLayoutWidget( + onPerformLayout: (Size size) { + if (!mounted) return; + _height = size.height; setState(() {}); }, - ); - return OnlyLayoutWidget( - key: _key, child: Padding( padding: widget.padding ?? .zero, child: widget.itemBuilder(context, 0), diff --git a/lib/pages/dynamics_topic/view.dart b/lib/pages/dynamics_topic/view.dart index f89bb8d27..edf9f5eee 100644 --- a/lib/pages/dynamics_topic/view.dart +++ b/lib/pages/dynamics_topic/view.dart @@ -159,7 +159,7 @@ class _DynTopicPageState extends State with DynMixin { Loading() => const SliverAppBar(), Success(:final response) when response != null => DynamicSliverAppBarMedium( pinned: true, - afterCalc: (value) => + onPerformLayout: (value) => _controller.appbarOffset = value - kToolbarHeight - padding.top, title: IgnorePointer(child: Text(response.topicItem!.name)), flexibleSpace: Container(