Last active
June 1, 2022 12:45
-
-
Save lukepighetti/bd5e081d418a7a0add032e254845b9ff to your computer and use it in GitHub Desktop.
Overlay widgets in any context... only issue, hot reload is broken
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart'; | |
import 'package:tuple/tuple.dart'; | |
import 'package:uuid/uuid.dart'; | |
class LocalOverlayScope extends StatefulWidget { | |
const LocalOverlayScope({Key? key, required this.child}) : super(key: key); | |
final Widget child; | |
@override | |
State<LocalOverlayScope> createState() => LocalOverlayScopeState(); | |
} | |
class LocalOverlayScopeState extends State<LocalOverlayScope> { | |
final _links = <String, Tuple3<LayerLink, Widget, _Params>>{}; | |
LayerLink registerWidget(String linkKey, Widget widget, _Params params) { | |
return (_links[linkKey] ??= Tuple3(LayerLink(), widget, params)).item1; | |
} | |
void unregisterWidget(String linkKey) { | |
_links.remove(linkKey); | |
} | |
@override | |
void initState() { | |
// would be nice to remove this build race | |
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {})); | |
super.initState(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Provider.value( | |
value: this, | |
child: Stack( | |
children: [ | |
widget.child, | |
for (final link in _links.entries) | |
CompositedTransformFollower( | |
key: ValueKey(link.key), | |
link: link.value.item1, | |
child: link.value.item2, | |
showWhenUnlinked: link.value.item3.showWhenUnlinked, | |
offset: link.value.item3.offset, | |
targetAnchor: link.value.item3.targetAnchor, | |
followerAnchor: link.value.item3.followerAnchor, | |
), | |
], | |
), | |
); | |
} | |
} | |
class LocalOverlayTarget extends StatefulWidget { | |
LocalOverlayTarget({ | |
Key? key, | |
required this.child, | |
required this.follower, | |
this.targetAnchor = Alignment.topCenter, | |
this.followerAnchor = Alignment.bottomCenter, | |
this.offset = Offset.zero, | |
this.showWhenUnlinked = true, | |
}) : super(key: key); | |
final Widget child; | |
final Widget follower; | |
final Alignment targetAnchor; | |
final Alignment followerAnchor; | |
final Offset offset; | |
final bool showWhenUnlinked; | |
@override | |
State<LocalOverlayTarget> createState() => _LocalOverlayTargetState(); | |
} | |
class _LocalOverlayTargetState extends State<LocalOverlayTarget> { | |
late final linkKey = Uuid().v4(); | |
late final scope = Provider.of<LocalOverlayScopeState>(context); | |
late final _params = _Params( | |
targetAnchor: widget.targetAnchor, | |
followerAnchor: widget.followerAnchor, | |
offset: widget.offset, | |
showWhenUnlinked: widget.showWhenUnlinked, | |
); | |
// would be nice to update this when follower or params are updated, | |
// because right now hot reload does not work | |
late LayerLink link = scope.registerWidget(linkKey, widget.follower, _params); | |
@override | |
void dispose() { | |
scope.unregisterWidget(linkKey); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return CompositedTransformTarget( | |
link: link, | |
child: widget.child, | |
); | |
} | |
} | |
class _Params { | |
_Params({ | |
this.targetAnchor = Alignment.topCenter, | |
this.followerAnchor = Alignment.bottomCenter, | |
this.offset = Offset.zero, | |
this.showWhenUnlinked = false, | |
}); | |
final Alignment targetAnchor; | |
final Alignment followerAnchor; | |
final Offset offset; | |
final bool showWhenUnlinked; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Internal ref: https://github.com/tonalfitness/mobile/pull/6285/files#diff-9ccadadfd9cc899e77dde8280f5e8b1f651a4a9353b09b8be34bed6cffc907a7