[infra_ui][overlar] Implement overlay anchor - widget part

This commit is contained in:
Jaylen Bian 2021-08-01 10:53:58 +08:00
parent a9c829b417
commit 80cb0f9fa1
3 changed files with 122 additions and 43 deletions

View File

@ -45,11 +45,11 @@ class OverlayScreen extends StatelessWidget {
ElevatedButton(
onPressed: () {
FlowyOverlay.of(context).insert(
const FlutterLogo(
widget: const FlutterLogo(
size: 200,
),
'overlay_flutter_logo',
null,
identifier: 'overlay_flutter_logo',
delegate: null,
);
},
child: const Text('Show Overlay'),

View File

@ -1,4 +1,5 @@
import 'package:dartz/dartz.dart' show Tuple3;
import 'package:flowy_infra_ui/src/flowy_overlay/overlay_layout_delegate.dart';
import 'package:flutter/material.dart';
/// Specifies how overlay are anchored to the SourceWidget
@ -110,14 +111,55 @@ class FlowyOverlay extends StatefulWidget {
class FlowyOverlayState extends State<FlowyOverlay> {
List<Tuple3<Widget, String, FlowyOverlayDelegate?>> _overlayList = [];
void insert({
/// Insert a overlay widget which frame is set by the widget, not the component.
/// Be sure to specify the offset and size using the `Postition` widget.
void insertCustom({
required Widget widget,
required String identifier,
FlowyOverlayDelegate? delegate,
}) {
setState(() {
_overlayList.add(Tuple3(widget, identifier, delegate));
});
_showOverlay(
widget: widget,
identifier: identifier,
shouldAnchor: false,
delegate: delegate,
);
}
void insertWithRect({
required Widget widget,
required String identifier,
required Offset anchorPosition,
required Size anchorSize,
AnchorDirection? anchorDirection,
FlowyOverlayDelegate? delegate,
}) {
_showOverlay(
widget: widget,
identifier: identifier,
shouldAnchor: true,
delegate: delegate,
anchorPosition: anchorPosition,
anchorSize: anchorSize,
anchorDirection: anchorDirection,
);
}
void insertWithAnchor({
required Widget widget,
required String identifier,
required BuildContext anchorContext,
AnchorDirection? anchorDirection,
FlowyOverlayDelegate? delegate,
}) {
_showOverlay(
widget: widget,
identifier: identifier,
shouldAnchor: true,
delegate: delegate,
anchorContext: anchorContext,
anchorDirection: anchorDirection,
);
}
void remove(String identifier) {
@ -142,6 +184,48 @@ class FlowyOverlayState extends State<FlowyOverlay> {
}
}
void _showOverlay({
required Widget widget,
required String identifier,
required bool shouldAnchor,
Offset? anchorPosition,
Size? anchorSize,
AnchorDirection? anchorDirection,
BuildContext? anchorContext,
FlowyOverlayDelegate? delegate,
}) {
Widget overlay = widget;
if (shouldAnchor) {
assert(
anchorPosition != null || anchorContext != null,
'Must provide `anchorPosition` or `anchorContext` to locating overlay.',
);
var targetAnchorPosition = anchorPosition;
if (anchorContext != null) {
RenderObject renderObject = anchorContext.findRenderObject()!;
assert(
renderObject is RenderBox,
'Unexpect non-RenderBox render object caught.',
);
final localOffset = (renderObject as RenderBox).localToGlobal(Offset.zero);
targetAnchorPosition ??= localOffset;
}
final anchorRect = targetAnchorPosition! & (anchorSize ?? Size.zero);
overlay = CustomSingleChildLayout(
delegate: OverlayLayoutDelegate(
anchorRect: anchorRect,
anchorDirection: anchorDirection ?? AnchorDirection.rightWithTopAligned,
),
child: widget,
);
}
setState(() {
_overlayList.add(Tuple3(overlay, identifier, delegate));
});
}
@override
Widget build(BuildContext context) {
final overlays = _overlayList.map((ele) => ele.value1);

View File

@ -1,43 +1,38 @@
// import 'dart:math' as math;
// import 'dart:ui';
import 'dart:math' as math;
import 'dart:ui';
// import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
// import 'flowy_overlay.dart';
import 'flowy_overlay.dart';
// class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
// OverlayLayoutDelegate({
// required this.route,
// required this.padding,
// required this.anchorPosition,
// required this.anchorDirection,
// });
class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
OverlayLayoutDelegate({
required this.anchorRect,
required this.anchorDirection,
});
// final OverlayPannelRoute route;
// final EdgeInsets padding;
// final AnchorDirection anchorDirection;
// final Offset anchorPosition;
final Rect anchorRect;
final AnchorDirection anchorDirection;
// @override
// bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
// return anchorPosition != oldDelegate.anchorPosition || anchorDirection != oldDelegate.anchorDirection;
// }
@override
bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
return anchorRect != oldDelegate.anchorRect || anchorDirection != oldDelegate.anchorDirection;
}
// @override
// Offset getPositionForChild(Size size, Size childSize) {
// // TODO: junlin - calculate child position
// return Offset.zero;
// }
@override
Size getSize(BoxConstraints constraints) {
return super.getSize(constraints);
}
// @override
// BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
// double maxHeight = math.max(0.0, constraints.maxHeight - padding.top - padding.bottom);
// double width = constraints.maxWidth;
// return BoxConstraints(
// minHeight: 0.0,
// maxHeight: maxHeight,
// minWidth: width,
// maxWidth: width,
// );
// }
// }
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
// TODO: junlin - calculate child constaints
return super.getConstraintsForChild(constraints);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
// TODO: junlin - calculate child position
return Offset(size.width / 2, size.height / 2);
}
}