Преглед изворни кода

Handle user taps on the padding area around the editor

Anatoly Pulyaevskiy пре 6 година
родитељ
комит
86b30018ef

+ 1
- 1
packages/zefyr/example/ios/Podfile.lock Прегледај датотеку

@@ -25,4 +25,4 @@ SPEC CHECKSUMS:
25 25
 
26 26
 PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2
27 27
 
28
-COCOAPODS: 1.5.2
28
+COCOAPODS: 1.5.3

+ 9
- 1
packages/zefyr/lib/src/widgets/editable_text.dart Прегледај датотеку

@@ -35,6 +35,7 @@ class ZefyrEditableText extends StatefulWidget {
35 35
     @required this.imageDelegate,
36 36
     this.autofocus: true,
37 37
     this.enabled: true,
38
+    this.padding: const EdgeInsets.symmetric(horizontal: 16.0),
38 39
   }) : super(key: key);
39 40
 
40 41
   final ZefyrController controller;
@@ -43,6 +44,9 @@ class ZefyrEditableText extends StatefulWidget {
43 44
   final bool autofocus;
44 45
   final bool enabled;
45 46
 
47
+  /// Padding around editable area.
48
+  final EdgeInsets padding;
49
+
46 50
   static ZefyrEditableTextScope of(BuildContext context) {
47 51
     final ZefyrEditableTextScope result =
48 52
         context.inheritFromWidgetOfExactType(ZefyrEditableTextScope);
@@ -123,11 +127,15 @@ class _ZefyrEditableTextState extends State<ZefyrEditableText>
123 127
     super.build(context); // See AutomaticKeepAliveState.
124 128
     ZefyrEditor.of(context);
125 129
 
130
+    Widget body = ListBody(children: _buildChildren(context));
131
+    if (widget.padding != null) {
132
+      body = new Padding(padding: widget.padding, child: body);
133
+    }
126 134
     final scrollable = SingleChildScrollView(
127 135
       padding: EdgeInsets.only(top: 16.0),
128 136
       physics: AlwaysScrollableScrollPhysics(),
129 137
       controller: _scrollController,
130
-      child: ListBody(children: _buildChildren(context)),
138
+      child: body,
131 139
     );
132 140
 
133 141
     final overlay = Overlay.of(context, debugRequiredFor: widget);

+ 2
- 3
packages/zefyr/lib/src/widgets/editor.dart Прегледај датотеку

@@ -159,10 +159,9 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
159 159
       imageDelegate: _imageDelegate,
160 160
       autofocus: widget.autofocus,
161 161
       enabled: widget.enabled,
162
+      padding: widget.padding,
162 163
     );
163
-    if (widget.padding != null) {
164
-      editable = new Padding(padding: widget.padding, child: editable);
165
-    }
164
+
166 165
     final children = <Widget>[];
167 166
     children.add(Expanded(child: editable));
168 167
     final toolbar = ZefyrToolbar(

+ 19
- 0
packages/zefyr/lib/src/widgets/render_context.dart Прегледај датотеку

@@ -94,6 +94,25 @@ class ZefyrRenderContext extends ChangeNotifier {
94 94
     }, orElse: _null);
95 95
   }
96 96
 
97
+  /// Returns closest render box to the specified global [point].
98
+  ///
99
+  /// If [point] is inside of one of active render boxes that box is returned.
100
+  /// Otherwise this method checks if [point] is to the left or to the right
101
+  /// side of a box, e.g. if vertical offset of this point is inside of one of
102
+  /// the active boxes. If it is then that box is returned.
103
+  RenderEditableProxyBox closestBoxForGlobalPoint(Offset point) {
104
+    assert(!_disposed);
105
+    RenderEditableProxyBox box = boxForGlobalPoint(point);
106
+    if (box != null) return box;
107
+
108
+    box = _activeBoxes.firstWhere((p) {
109
+      final localPoint = p.globalToLocal(point);
110
+      return (localPoint.dy >= 0 && localPoint.dy < p.size.height);
111
+    }, orElse: _null);
112
+
113
+    return box;
114
+  }
115
+
97 116
   static Null _null() => null;
98 117
 
99 118
   @override

+ 6
- 2
packages/zefyr/lib/src/widgets/selection.dart Прегледај датотеку

@@ -216,8 +216,12 @@ class _ZefyrSelectionOverlayState extends State<ZefyrSelectionOverlay>
216 216
     HitTestResult result = new HitTestResult();
217 217
     WidgetsBinding.instance.hitTest(result, globalPoint);
218 218
 
219
-    final box = _getEditableBox(result);
220
-    if (box == null) return;
219
+    RenderEditableProxyBox box = _getEditableBox(result);
220
+    if (box == null) {
221
+      final editable = ZefyrEditableText.of(context);
222
+      box = editable.renderContext.closestBoxForGlobalPoint(globalPoint);
223
+    }
224
+    if (box == null) return null;
221 225
 
222 226
     final localPoint = box.globalToLocal(globalPoint);
223 227
     final position = box.getPositionForOffset(localPoint);

+ 19
- 0
packages/zefyr/test/widgets/selection_test.dart Прегледај датотеку

@@ -33,5 +33,24 @@ void main() {
33 33
       await editor.unfocus();
34 34
       expect(editor.findSelectionHandle(), findsNothing);
35 35
     });
36
+
37
+    testWidgets('tap outside of text area finds closest paragraph',
38
+        (tester) async {
39
+      final editor = new EditorSandBox(tester: tester);
40
+      await editor.tapEditor();
41
+      editor.controller
42
+          .updateSelection(new TextSelection.collapsed(offset: 10));
43
+      await tester.pumpAndSettle();
44
+      expect(editor.controller.selection.extentOffset, 10);
45
+
46
+      RenderEditableParagraph renderObject =
47
+          tester.firstRenderObject(find.byType(EditableRichText));
48
+      var offset = renderObject.localToGlobal(Offset.zero);
49
+      offset += Offset(-5.0, 5.0);
50
+      await tester.tapAt(offset);
51
+      await tester.pumpAndSettle();
52
+      expect(editor.controller.selection.isCollapsed, isTrue);
53
+      expect(editor.controller.selection.extentOffset, 0);
54
+    });
36 55
   });
37 56
 }