Explorar el Código

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

Jaylen Bian hace 3 años
padre
commit
80cb0f9fa1

+ 3 - 3
app_flowy/packages/flowy_infra_ui/example/lib/overlay/overlay_screen.dart

@@ -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'),

+ 88 - 4
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart

@@ -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);

+ 38 - 43
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_layout_delegate.dart

@@ -1,43 +1,38 @@
-// import 'dart:math' as math;
-// import 'dart:ui';
-
-// import 'package:flutter/material.dart';
-
-// import 'flowy_overlay.dart';
-
-// class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
-//   OverlayLayoutDelegate({
-//     required this.route,
-//     required this.padding,
-//     required this.anchorPosition,
-//     required this.anchorDirection,
-//   });
-
-//   final OverlayPannelRoute route;
-//   final EdgeInsets padding;
-//   final AnchorDirection anchorDirection;
-//   final Offset anchorPosition;
-
-//   @override
-//   bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
-//     return anchorPosition != oldDelegate.anchorPosition || anchorDirection != oldDelegate.anchorDirection;
-//   }
-
-//   @override
-//   Offset getPositionForChild(Size size, Size childSize) {
-//     // TODO: junlin - calculate child position
-//     return Offset.zero;
-//   }
-
-//   @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,
-//     );
-//   }
-// }
+import 'dart:math' as math;
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+
+import 'flowy_overlay.dart';
+
+class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
+  OverlayLayoutDelegate({
+    required this.anchorRect,
+    required this.anchorDirection,
+  });
+
+  final Rect anchorRect;
+  final AnchorDirection anchorDirection;
+
+  @override
+  bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
+    return anchorRect != oldDelegate.anchorRect || anchorDirection != oldDelegate.anchorDirection;
+  }
+
+  @override
+  Size getSize(BoxConstraints constraints) {
+    return super.getSize(constraints);
+  }
+
+  @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);
+  }
+}