[infra_ui][overlay] Implement overlap behavior and update example proj

This commit is contained in:
Jaylen Bian 2021-08-02 15:03:52 +08:00
parent 39ac4b59be
commit eb4728e346
3 changed files with 123 additions and 12 deletions

View File

@ -20,8 +20,8 @@ class OverlayItem extends DemoItem {
} }
} }
class OverlayDemoAnchorDirection extends ChangeNotifier { class OverlayDemoConfiguration extends ChangeNotifier {
OverlayDemoAnchorDirection(this._anchorDirection); OverlayDemoConfiguration(this._anchorDirection, this._overlapBehaviour);
AnchorDirection _anchorDirection; AnchorDirection _anchorDirection;
@ -31,6 +31,15 @@ class OverlayDemoAnchorDirection extends ChangeNotifier {
_anchorDirection = value; _anchorDirection = value;
notifyListeners(); notifyListeners();
} }
OverlapBehaviour _overlapBehaviour;
OverlapBehaviour get overlapBehaviour => _overlapBehaviour;
set overlapBehaviour(OverlapBehaviour value) {
_overlapBehaviour = value;
notifyListeners();
}
} }
class OverlayScreen extends StatelessWidget { class OverlayScreen extends StatelessWidget {
@ -43,7 +52,7 @@ class OverlayScreen extends StatelessWidget {
title: const Text('Overlay Demo'), title: const Text('Overlay Demo'),
), ),
body: ChangeNotifierProvider( body: ChangeNotifierProvider(
create: (context) => OverlayDemoAnchorDirection(AnchorDirection.rightWithTopAligned), create: (context) => OverlayDemoConfiguration(AnchorDirection.rightWithTopAligned, OverlapBehaviour.stretch),
child: Builder(builder: (providerContext) { child: Builder(builder: (providerContext) {
return Center( return Center(
child: ConstrainedBox( child: ConstrainedBox(
@ -80,10 +89,10 @@ class OverlayScreen extends StatelessWidget {
), ),
const SizedBox(height: 24.0), const SizedBox(height: 24.0),
DropdownButton<AnchorDirection>( DropdownButton<AnchorDirection>(
value: providerContext.watch<OverlayDemoAnchorDirection>().anchorDirection, value: providerContext.watch<OverlayDemoConfiguration>().anchorDirection,
onChanged: (AnchorDirection? newValue) { onChanged: (AnchorDirection? newValue) {
if (newValue != null) { if (newValue != null) {
providerContext.read<OverlayDemoAnchorDirection>().anchorDirection = newValue; providerContext.read<OverlayDemoConfiguration>().anchorDirection = newValue;
} }
}, },
items: AnchorDirection.values.map((AnchorDirection classType) { items: AnchorDirection.values.map((AnchorDirection classType) {
@ -91,6 +100,18 @@ class OverlayScreen extends StatelessWidget {
}).toList(), }).toList(),
), ),
const SizedBox(height: 24.0), const SizedBox(height: 24.0),
DropdownButton<OverlapBehaviour>(
value: providerContext.watch<OverlayDemoConfiguration>().overlapBehaviour,
onChanged: (OverlapBehaviour? newValue) {
if (newValue != null) {
providerContext.read<OverlayDemoConfiguration>().overlapBehaviour = newValue;
}
},
items: OverlapBehaviour.values.map((OverlapBehaviour classType) {
return DropdownMenuItem<OverlapBehaviour>(value: classType, child: Text(classType.toString()));
}).toList(),
),
const SizedBox(height: 24.0),
Builder(builder: (buttonContext) { Builder(builder: (buttonContext) {
return SizedBox( return SizedBox(
height: 100, height: 100,
@ -98,7 +119,7 @@ class OverlayScreen extends StatelessWidget {
onPressed: () { onPressed: () {
FlowyOverlay.of(context).insertWithAnchor( FlowyOverlay.of(context).insertWithAnchor(
widget: SizedBox( widget: SizedBox(
width: 100, width: 300,
height: 50, height: 50,
child: Card( child: Card(
color: Colors.grey[200], color: Colors.grey[200],
@ -112,7 +133,8 @@ class OverlayScreen extends StatelessWidget {
identifier: 'overlay_anchored_card', identifier: 'overlay_anchored_card',
delegate: null, delegate: null,
anchorContext: buttonContext, anchorContext: buttonContext,
anchorDirection: providerContext.read<OverlayDemoAnchorDirection>().anchorDirection, anchorDirection: providerContext.read<OverlayDemoConfiguration>().anchorDirection,
overlapBehaviour: providerContext.read<OverlayDemoConfiguration>().overlapBehaviour,
); );
}, },
child: const Text('Show Anchored Overlay'), child: const Text('Show Anchored Overlay'),
@ -140,7 +162,8 @@ class OverlayScreen extends StatelessWidget {
delegate: null, delegate: null,
anchorPosition: Offset(0, windowSize.height - 200), anchorPosition: Offset(0, windowSize.height - 200),
anchorSize: Size.zero, anchorSize: Size.zero,
anchorDirection: providerContext.read<OverlayDemoAnchorDirection>().anchorDirection, anchorDirection: providerContext.read<OverlayDemoConfiguration>().anchorDirection,
overlapBehaviour: providerContext.read<OverlayDemoConfiguration>().overlapBehaviour,
); );
}, },
child: const Text('Show Positioned Overlay'), child: const Text('Show Positioned Overlay'),

View File

@ -28,8 +28,7 @@ enum AnchorDirection {
custom, custom,
} }
// TODO: junlin - support overlap behaviour /// The behaviour of overlay when overlap with anchor widget
/// [Unsupported] The behaviour of overlay when overlap with anchor widget
enum OverlapBehaviour { enum OverlapBehaviour {
/// Maintain overlay size, which may cover the anchor widget. /// Maintain overlay size, which may cover the anchor widget.
none, none,
@ -144,6 +143,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
required Size anchorSize, required Size anchorSize,
AnchorDirection? anchorDirection, AnchorDirection? anchorDirection,
FlowyOverlayDelegate? delegate, FlowyOverlayDelegate? delegate,
OverlapBehaviour? overlapBehaviour,
}) { }) {
_showOverlay( _showOverlay(
widget: widget, widget: widget,
@ -153,6 +153,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
anchorPosition: anchorPosition, anchorPosition: anchorPosition,
anchorSize: anchorSize, anchorSize: anchorSize,
anchorDirection: anchorDirection, anchorDirection: anchorDirection,
overlapBehaviour: overlapBehaviour,
); );
} }
@ -162,6 +163,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
required BuildContext anchorContext, required BuildContext anchorContext,
AnchorDirection? anchorDirection, AnchorDirection? anchorDirection,
FlowyOverlayDelegate? delegate, FlowyOverlayDelegate? delegate,
OverlapBehaviour? overlapBehaviour,
}) { }) {
_showOverlay( _showOverlay(
widget: widget, widget: widget,
@ -170,6 +172,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
delegate: delegate, delegate: delegate,
anchorContext: anchorContext, anchorContext: anchorContext,
anchorDirection: anchorDirection, anchorDirection: anchorDirection,
overlapBehaviour: overlapBehaviour,
); );
} }

View File

@ -29,8 +29,93 @@ class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
case OverlapBehaviour.none: case OverlapBehaviour.none:
return constraints.loosen(); return constraints.loosen();
case OverlapBehaviour.stretch: case OverlapBehaviour.stretch:
// TODO: junlin - resize when overlapBehaviour == .stretch BoxConstraints childConstraints;
return constraints.loosen(); switch (anchorDirection) {
case AnchorDirection.topLeft:
childConstraints = BoxConstraints.loose(Size(
anchorRect.left,
anchorRect.top,
));
break;
case AnchorDirection.topRight:
childConstraints = BoxConstraints.loose(Size(
constraints.maxWidth - anchorRect.right,
anchorRect.top,
));
break;
case AnchorDirection.bottomLeft:
childConstraints = BoxConstraints.loose(Size(
anchorRect.left,
constraints.maxHeight - anchorRect.bottom,
));
break;
case AnchorDirection.bottomRight:
childConstraints = BoxConstraints.loose(Size(
constraints.maxWidth - anchorRect.right,
constraints.maxHeight - anchorRect.bottom,
));
break;
case AnchorDirection.rightWithTopAligned:
childConstraints = BoxConstraints.loose(Size(
constraints.maxWidth - anchorRect.right,
constraints.maxHeight - anchorRect.top,
));
break;
case AnchorDirection.rightWithCenterAligned:
childConstraints = BoxConstraints.loose(Size(
constraints.maxWidth - anchorRect.right,
constraints.maxHeight,
));
break;
case AnchorDirection.rightWithBottomAligned:
childConstraints = BoxConstraints.loose(Size(
constraints.maxWidth - anchorRect.right,
anchorRect.bottom,
));
break;
case AnchorDirection.bottomWithLeftAligned:
childConstraints = BoxConstraints.loose(Size(
anchorRect.left,
constraints.maxHeight - anchorRect.bottom,
));
break;
case AnchorDirection.bottomWithCenterAligned:
childConstraints = BoxConstraints.loose(Size(
constraints.maxWidth,
constraints.maxHeight - anchorRect.bottom,
));
break;
case AnchorDirection.bottomWithRightAligned:
childConstraints = BoxConstraints.loose(Size(
anchorRect.right,
constraints.maxHeight - anchorRect.bottom,
));
break;
case AnchorDirection.leftWithTopAligned:
childConstraints = BoxConstraints.loose(Size(
anchorRect.left,
constraints.maxHeight - anchorRect.top,
));
break;
case AnchorDirection.leftWithCenterAligned:
childConstraints = BoxConstraints.loose(Size(
anchorRect.left,
constraints.maxHeight,
));
break;
case AnchorDirection.leftWithBottomAligned:
childConstraints = BoxConstraints.loose(Size(
anchorRect.left,
anchorRect.bottom,
));
break;
case AnchorDirection.custom:
childConstraints = constraints.loosen();
break;
default:
throw UnimplementedError();
}
return childConstraints;
} }
} }