feat: add flags to popover

This commit is contained in:
Vincent Chan 2022-08-30 18:26:44 +08:00
parent 33e45a86c4
commit 27557c52a3
2 changed files with 54 additions and 64 deletions

View File

@ -7,16 +7,7 @@ class PopoverMenu extends StatefulWidget {
} }
class _PopoverMenuState extends State<PopoverMenu> { class _PopoverMenuState extends State<PopoverMenu> {
final PopoverMutex exclusive = PopoverMutex(); final PopoverMutex popOverMutex = PopoverMutex();
late PopoverController firstPopover;
late PopoverController secondPopover;
@override
void initState() {
firstPopover = PopoverController(mutex: exclusive);
secondPopover = PopoverController(mutex: exclusive);
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -27,7 +18,9 @@ class _PopoverMenuState extends State<PopoverMenu> {
child: ListView(children: [ child: ListView(children: [
const Text("App"), const Text("App"),
Popover( Popover(
controller: firstPopover, triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
mutex: popOverMutex,
offset: const Offset(10, 0), offset: const Offset(10, 0),
targetAnchor: Alignment.topRight, targetAnchor: Alignment.topRight,
followerAnchor: Alignment.topLeft, followerAnchor: Alignment.topLeft,
@ -35,19 +28,14 @@ class _PopoverMenuState extends State<PopoverMenu> {
return PopoverMenu(); return PopoverMenu();
}, },
child: TextButton( child: TextButton(
onPressed: () { onPressed: () {},
firstPopover.show();
},
onHover: (value) {
if (value) {
firstPopover.show();
}
},
child: const Text("First"), child: const Text("First"),
), ),
), ),
Popover( Popover(
controller: secondPopover, triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
mutex: popOverMutex,
offset: const Offset(10, 0), offset: const Offset(10, 0),
targetAnchor: Alignment.topRight, targetAnchor: Alignment.topRight,
followerAnchor: Alignment.topLeft, followerAnchor: Alignment.topLeft,
@ -55,14 +43,7 @@ class _PopoverMenuState extends State<PopoverMenu> {
return PopoverMenu(); return PopoverMenu();
}, },
child: TextButton( child: TextButton(
onPressed: () { onPressed: () {},
secondPopover.show();
},
onHover: (value) {
if (value) {
secondPopover.show();
}
},
child: const Text("Second"), child: const Text("Second"),
), ),
), ),
@ -72,14 +53,12 @@ class _PopoverMenuState extends State<PopoverMenu> {
} }
class ExampleButton extends StatelessWidget { class ExampleButton extends StatelessWidget {
final PopoverController _popover = PopoverController();
final String label; final String label;
final Alignment targetAnchor; final Alignment targetAnchor;
final Alignment followerAnchor; final Alignment followerAnchor;
final Offset? offset; final Offset? offset;
ExampleButton({ const ExampleButton({
Key? key, Key? key,
required this.label, required this.label,
this.targetAnchor = Alignment.topLeft, this.targetAnchor = Alignment.topLeft,
@ -90,16 +69,11 @@ class ExampleButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Popover( return Popover(
controller: _popover,
targetAnchor: targetAnchor, targetAnchor: targetAnchor,
followerAnchor: followerAnchor, followerAnchor: followerAnchor,
triggerActions: PopoverTriggerActionFlags.click,
offset: offset, offset: offset,
child: TextButton( child: TextButton(child: Text(label), onPressed: () {}),
onPressed: (() {
_popover.show();
}),
child: Text(label),
),
popupBuilder: (BuildContext context) { popupBuilder: (BuildContext context) {
return PopoverMenu(); return PopoverMenu();
}, },

View File

@ -3,32 +3,26 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class PopoverMutex { class PopoverMutex {
PopoverController? controller; PopoverState? state;
} }
class PopoverController { class PopoverController {
PopoverState? state; PopoverState? state;
PopoverMutex? mutex;
PopoverController({this.mutex});
close() { close() {
state?.close(); state?.close();
if (mutex != null && mutex!.controller == this) {
mutex!.controller = null;
}
} }
show() { show() {
if (mutex != null) {
debugPrint("show popover");
mutex!.controller?.close();
mutex!.controller = this;
}
state?.showOverlay(); state?.showOverlay();
} }
} }
class PopoverTriggerActionFlags {
static int click = 0x01;
static int hover = 0x02;
}
class Popover extends StatefulWidget { class Popover extends StatefulWidget {
final Widget child; final Widget child;
final PopoverController? controller; final PopoverController? controller;
@ -37,6 +31,8 @@ class Popover extends StatefulWidget {
final Alignment targetAnchor; final Alignment targetAnchor;
final Alignment followerAnchor; final Alignment followerAnchor;
final Widget Function(BuildContext context) popupBuilder; final Widget Function(BuildContext context) popupBuilder;
final int triggerActions;
final PopoverMutex? mutex;
final void Function()? onClose; final void Function()? onClose;
const Popover({ const Popover({
@ -48,6 +44,8 @@ class Popover extends StatefulWidget {
this.maskDecoration, this.maskDecoration,
this.targetAnchor = Alignment.topLeft, this.targetAnchor = Alignment.topLeft,
this.followerAnchor = Alignment.topLeft, this.followerAnchor = Alignment.topLeft,
this.triggerActions = 0,
this.mutex,
this.onClose, this.onClose,
}) : super(key: key); }) : super(key: key);
@ -59,20 +57,12 @@ class PopoverState extends State<Popover> {
final LayerLink layerLink = LayerLink(); final LayerLink layerLink = LayerLink();
OverlayEntry? _overlayEntry; OverlayEntry? _overlayEntry;
bool hasMask = true; bool hasMask = true;
late TapGestureRecognizer _recognizer;
static PopoverState? _popoverWithMask; static PopoverState? _popoverWithMask;
@override @override
void initState() { void initState() {
widget.controller?.state = this; widget.controller?.state = this;
_recognizer = TapGestureRecognizer();
_recognizer.onTapDown = (details) {
debugPrint("ggg tapdown");
};
_recognizer.onTap = (() {
debugPrint("ggg tap");
});
super.initState(); super.initState();
} }
@ -80,12 +70,19 @@ class PopoverState extends State<Popover> {
debugPrint("show overlay"); debugPrint("show overlay");
close(); close();
if (widget.mutex != null) {
if (widget.mutex!.state != null && widget.mutex!.state != this) {
widget.mutex!.state!.close();
}
widget.mutex!.state = this;
}
if (_popoverWithMask == null) { if (_popoverWithMask == null) {
_popoverWithMask = this; _popoverWithMask = this;
} else { } else {
hasMask = false; hasMask = false;
} }
debugPrint("has mask: $hasMask");
final newEntry = OverlayEntry(builder: (context) { final newEntry = OverlayEntry(builder: (context) {
final children = <Widget>[]; final children = <Widget>[];
@ -126,6 +123,10 @@ class PopoverState extends State<Popover> {
widget.onClose!(); widget.onClose!();
} }
} }
if (widget.mutex?.state == this) {
widget.mutex!.state = null;
}
} }
@override @override
@ -135,15 +136,30 @@ class PopoverState extends State<Popover> {
super.deactivate(); super.deactivate();
} }
@override _handleTargetPointerDown(PointerDownEvent event) {
void dispose() { if (widget.triggerActions & PopoverTriggerActionFlags.click != 0) {
_recognizer.dispose(); showOverlay();
super.dispose(); }
}
_handleTargetPointerEnter(PointerEnterEvent event) {
if (widget.triggerActions & PopoverTriggerActionFlags.hover != 0) {
showOverlay();
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CompositedTransformTarget(link: layerLink, child: widget.child); return CompositedTransformTarget(
link: layerLink,
child: MouseRegion(
onEnter: _handleTargetPointerEnter,
child: Listener(
onPointerDown: _handleTargetPointerDown,
child: widget.child,
),
),
);
} }
} }