mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-22 17:18:41 +00:00
@@ -1,8 +1,8 @@
|
||||
import 'package:PiliPlus/common/widgets/only_layout_widget.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// https://github.com/flutter/flutter/issues/18345#issuecomment-1627644396
|
||||
class DynamicSliverAppBarMedium extends StatefulWidget {
|
||||
const DynamicSliverAppBarMedium({
|
||||
this.flexibleSpace,
|
||||
@@ -93,56 +93,45 @@ class DynamicSliverAppBarMedium extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _DynamicSliverAppBarMediumState extends State<DynamicSliverAppBarMedium> {
|
||||
final GlobalKey _childKey = GlobalKey();
|
||||
|
||||
// As long as the height is 0 instead of the sliver app bar a sliver to box adapter will be used
|
||||
// to calculate dynamically the size for the sliver app bar
|
||||
double _height = 0;
|
||||
|
||||
void _updateHeight() {
|
||||
// Gets the new height and updates the sliver app bar. Needs to be called after the last frame has been rebuild
|
||||
// otherwise this will throw an error
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
if (_childKey.currentContext == null) return;
|
||||
setState(() {
|
||||
_height = (_childKey.currentContext!.findRenderObject()! as RenderBox)
|
||||
.size
|
||||
.height;
|
||||
widget.afterCalc?.call(_height);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
final GlobalKey _key = GlobalKey();
|
||||
double? _height;
|
||||
double? _width;
|
||||
late double _topPadding;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_topPadding = MediaQuery.viewPaddingOf(context).top;
|
||||
final width = MediaQuery.widthOf(context);
|
||||
if (_width != width) {
|
||||
_width = width;
|
||||
_height = 0;
|
||||
_updateHeight();
|
||||
_height = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//Needed to lay out the flexibleSpace the first time, so we can calculate its intrinsic height
|
||||
if (_height == 0) {
|
||||
if (_height == null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_height =
|
||||
(_key.currentContext!.findRenderObject() as RenderBox).size.height;
|
||||
widget.afterCalc?.call(_height!);
|
||||
setState(() {});
|
||||
});
|
||||
return SliverToBoxAdapter(
|
||||
child: UnconstrainedBox(
|
||||
alignment: Alignment.topLeft,
|
||||
child: SizedBox(
|
||||
key: _childKey,
|
||||
width: _width,
|
||||
child: widget.flexibleSpace,
|
||||
child: OnlyLayoutWidget(
|
||||
child: UnconstrainedBox(
|
||||
alignment: Alignment.topLeft,
|
||||
child: SizedBox(
|
||||
key: _key,
|
||||
width: _width,
|
||||
child: widget.flexibleSpace,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final padding = MediaQuery.viewPaddingOf(context).top;
|
||||
return SliverAppBar.medium(
|
||||
leading: widget.leading,
|
||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||
@@ -170,8 +159,8 @@ class _DynamicSliverAppBarMediumState extends State<DynamicSliverAppBarMedium> {
|
||||
onStretchTrigger: widget.onStretchTrigger,
|
||||
shape: widget.shape,
|
||||
toolbarHeight: kToolbarHeight,
|
||||
collapsedHeight: kToolbarHeight + padding + 1,
|
||||
expandedHeight: _height - padding,
|
||||
collapsedHeight: kToolbarHeight + _topPadding + 1,
|
||||
expandedHeight: _height! - _topPadding,
|
||||
leadingWidth: widget.leadingWidth,
|
||||
toolbarTextStyle: widget.toolbarTextStyle,
|
||||
titleTextStyle: widget.titleTextStyle,
|
||||
|
||||
17
lib/common/widgets/only_layout_widget.dart
Normal file
17
lib/common/widgets/only_layout_widget.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart' show RenderProxyBox;
|
||||
|
||||
class OnlyLayoutWidget extends SingleChildRenderObjectWidget {
|
||||
const OnlyLayoutWidget({
|
||||
super.key,
|
||||
super.child,
|
||||
});
|
||||
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) => Layout();
|
||||
}
|
||||
|
||||
class Layout extends RenderProxyBox {
|
||||
@override
|
||||
void paint(PaintingContext context, Offset offset) {}
|
||||
}
|
||||
@@ -1,88 +1,61 @@
|
||||
import 'package:PiliPlus/common/widgets/only_layout_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// https://stackoverflow.com/a/76605401
|
||||
|
||||
class SelfSizedHorizontalList extends StatefulWidget {
|
||||
final Widget Function(int index) childBuilder;
|
||||
final int itemCount;
|
||||
final double gapSize;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final ScrollController? controller;
|
||||
|
||||
const SelfSizedHorizontalList({
|
||||
super.key,
|
||||
required this.childBuilder,
|
||||
required this.itemCount,
|
||||
this.gapSize = 5,
|
||||
this.padding,
|
||||
required this.itemBuilder,
|
||||
required this.separatorBuilder,
|
||||
this.controller,
|
||||
this.padding,
|
||||
});
|
||||
|
||||
final int itemCount;
|
||||
final EdgeInsets? padding;
|
||||
final IndexedWidgetBuilder itemBuilder;
|
||||
final IndexedWidgetBuilder separatorBuilder;
|
||||
final ScrollController? controller;
|
||||
|
||||
@override
|
||||
State<SelfSizedHorizontalList> createState() =>
|
||||
_SelfSizedHorizontalListState();
|
||||
}
|
||||
|
||||
class _SelfSizedHorizontalListState extends State<SelfSizedHorizontalList> {
|
||||
final infoKey = GlobalKey();
|
||||
|
||||
double? prevHeight;
|
||||
double? get height {
|
||||
if (prevHeight != null) return prevHeight;
|
||||
prevHeight = infoKey.globalPaintBounds?.height;
|
||||
return prevHeight;
|
||||
}
|
||||
|
||||
bool get isInit => height == null;
|
||||
|
||||
// @override
|
||||
// void didUpdateWidget(SelfSizedHorizontalList oldWidget) {
|
||||
// super.didUpdateWidget(oldWidget);
|
||||
// if (BuildConfig.isDebug) {
|
||||
// prevHeight = null;
|
||||
// }
|
||||
// }
|
||||
final _key = GlobalKey();
|
||||
double? _height;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (height == null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((v) => setState(() {}));
|
||||
}
|
||||
if (widget.itemCount == 0) return const SizedBox.shrink();
|
||||
if (isInit) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
if (_height == null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) {
|
||||
_height = (_key.currentContext!.findRenderObject() as RenderBox)
|
||||
.size
|
||||
.height;
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
return OnlyLayoutWidget(
|
||||
key: _key,
|
||||
child: Padding(
|
||||
key: infoKey,
|
||||
padding: widget.padding ?? EdgeInsets.zero,
|
||||
child: widget.childBuilder(0),
|
||||
padding: widget.padding ?? .zero,
|
||||
child: widget.itemBuilder(context, 0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
height: height,
|
||||
height: _height,
|
||||
child: ListView.separated(
|
||||
controller: widget.controller,
|
||||
scrollDirection: .horizontal,
|
||||
padding: widget.padding,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: widget.itemCount,
|
||||
itemBuilder: (c, i) => widget.childBuilder(i),
|
||||
separatorBuilder: (c, i) => SizedBox(width: widget.gapSize),
|
||||
controller: widget.controller,
|
||||
itemBuilder: widget.itemBuilder,
|
||||
separatorBuilder: widget.separatorBuilder,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension GlobalKeyExtension on GlobalKey {
|
||||
Rect? get globalPaintBounds {
|
||||
final renderObject = currentContext?.findRenderObject();
|
||||
final translation = renderObject?.getTransformTo(null).getTranslation();
|
||||
if (translation != null && renderObject?.paintBounds != null) {
|
||||
final offset = Offset(translation.x, translation.y);
|
||||
return renderObject!.paintBounds.shift(offset);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user