Last active
December 11, 2023 13:57
-
-
Save hawkkiller/9385a561eecab9acd12bcd64e0d42e55 to your computer and use it in GitHub Desktop.
A widget that shows a popup relative to a target widget.
This file contains 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'; | |
/// A widget that shows a popup relative to a target widget. | |
/// | |
/// The popup is declaratively shown/hidden using an [OverlayPortalController]. | |
/// | |
/// It is positioned relative to the target widget using the [followerAnchor] and [targetAnchor] properties. | |
class Popup extends StatefulWidget { | |
const Popup({ | |
required this.child, | |
required this.follower, | |
required this.controller, | |
this.offset = Offset.zero, | |
this.followerAnchor = Alignment.topCenter, | |
this.targetAnchor = Alignment.bottomCenter, | |
super.key, | |
}); | |
/// The target widget that will be used to position the follower widget. | |
final Widget child; | |
/// The widget that will be positioned relative to the target widget. | |
final Widget follower; | |
/// The controller that will be used to show/hide the overlay. | |
final OverlayPortalController controller; | |
/// The alignment of the follower widget relative to the target widget. | |
/// | |
/// Defaults to [Alignment.topCenter]. | |
final Alignment followerAnchor; | |
/// The alignment of the target widget relative to the follower widget. | |
/// | |
/// Defaults to [Alignment.bottomCenter]. | |
final Alignment targetAnchor; | |
/// The offset of the follower widget relative to the target widget. | |
/// This is useful for fine-tuning the position of the follower widget. | |
/// | |
/// Defaults to [Offset.zero]. | |
final Offset offset; | |
@override | |
State<Popup> createState() => _PopupState(); | |
} | |
class _PopupState extends State<Popup> { | |
/// The link between the target widget and the follower widget. | |
final _layerLink = LayerLink(); | |
@override | |
Widget build(BuildContext context) { | |
return CompositedTransformTarget( | |
// Link the target widget to the follower widget. | |
link: _layerLink, | |
child: OverlayPortal( | |
controller: widget.controller, | |
child: widget.child, | |
overlayChildBuilder: (BuildContext context) { | |
// It is needed to wrap the follower widget in a widget that fills the space of the overlay. | |
// This is needed to make sure that the follower widget is positioned relative to the target widget. | |
// If not wrapped, the follower widget will fill the screen and be positioned incorrectly. | |
return Align( | |
child: CompositedTransformFollower( | |
// Link the follower widget to the target widget. | |
link: _layerLink, | |
// The follower widget should not be shown when the link is broken. | |
showWhenUnlinked: false, | |
followerAnchor: widget.followerAnchor, | |
targetAnchor: widget.targetAnchor, | |
offset: widget.offset, | |
child: widget.follower, | |
), | |
); | |
}, | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment