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

View File

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

View File

@ -29,8 +29,93 @@ class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
case OverlapBehaviour.none:
return constraints.loosen();
case OverlapBehaviour.stretch:
// TODO: junlin - resize when overlapBehaviour == .stretch
return constraints.loosen();
BoxConstraints childConstraints;
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;
}
}