Commit 527fddc6 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Port EditableText to Scrollable2 (#8167)

parent 3985ddbc
......@@ -28,7 +28,7 @@ export 'src/rendering/block.dart';
export 'src/rendering/box.dart';
export 'src/rendering/custom_layout.dart';
export 'src/rendering/debug.dart';
export 'src/rendering/editable_line.dart';
export 'src/rendering/editable.dart';
export 'src/rendering/error.dart';
export 'src/rendering/flex.dart';
export 'src/rendering/flow.dart';
......
......@@ -147,7 +147,6 @@ class _InputFieldState extends State<InputField> {
cursorColor: themeData.textSelectionColor,
selectionColor: themeData.textSelectionColor,
selectionControls: materialTextSelectionControls,
platform: Theme.of(context).platform,
keyboardType: config.keyboardType,
onChanged: config.onChanged,
onSubmitted: config.onSubmitted,
......
......@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:ui' as ui show TextBox;
import 'package:flutter/gestures.dart';
import 'package:meta/meta.dart';
import 'box.dart';
import 'object.dart';
import 'viewport.dart';
import 'viewport_offset.dart';
const double _kCaretGap = 1.0; // pixels
const double _kCaretHeightOffset = 2.0; // pixels
......@@ -39,14 +41,6 @@ class TextSelectionPoint {
final TextDirection direction;
}
/// Signature for the callback used by [RenderEditable] to determine the paint offset when
/// the dimensions of the render box change.
///
/// The return value should be the new paint offset to use.
///
/// Used by [RenderEditable.onPaintOffsetUpdateNeeded].
typedef Offset RenderEditablePaintOffsetNeededCallback(ViewportDimensions dimensions, Rect caretRect);
/// A single line of editable text.
class RenderEditable extends RenderBox {
/// Creates a render object for a single line of editable text.
......@@ -58,15 +52,18 @@ class RenderEditable extends RenderBox {
Color selectionColor,
double textScaleFactor: 1.0,
TextSelection selection,
@required ViewportOffset offset,
this.onSelectionChanged,
Offset paintOffset: Offset.zero,
this.onPaintOffsetUpdateNeeded,
}) : _textPainter = new TextPainter(text: text, textScaleFactor: textScaleFactor),
_cursorColor = cursorColor,
_showCursor = showCursor,
_maxLines = maxLines,
_selection = selection,
_paintOffset = paintOffset {
_offset = offset {
assert(showCursor != null);
assert(maxLines != null);
assert(textScaleFactor != null);
assert(offset != null);
assert(!showCursor || cursorColor != null);
_tap = new TapGestureRecognizer()
..onTapDown = _handleTapDown
......@@ -79,9 +76,6 @@ class RenderEditable extends RenderBox {
/// Called when the selection changes.
SelectionChangedHandler onSelectionChanged;
/// Called when the inner or outer dimensions of this render object change.
RenderEditablePaintOffsetNeededCallback onPaintOffsetUpdateNeeded;
/// The text to display
TextSpan get text => _textPainter.text;
final TextPainter _textPainter;
......@@ -106,6 +100,7 @@ class RenderEditable extends RenderBox {
bool get showCursor => _showCursor;
bool _showCursor;
set showCursor(bool value) {
assert(value != null);
if (_showCursor == value)
return;
_showCursor = value;
......@@ -118,6 +113,7 @@ class RenderEditable extends RenderBox {
int get maxLines => _maxLines;
int _maxLines;
set maxLines(int value) {
assert(value != null);
if (_maxLines == value)
return;
_maxLines = value;
......@@ -165,15 +161,58 @@ class RenderEditable extends RenderBox {
/// If the text content is larger than the editable line itself, the editable
/// line clips the text. This property controls which part of the text is
/// visible by shifting the text by the given offset before clipping.
Offset get paintOffset => _paintOffset;
Offset _paintOffset;
set paintOffset(Offset value) {
if (_paintOffset == value)
ViewportOffset get offset => _offset;
ViewportOffset _offset;
set offset(ViewportOffset value) {
assert(value != null);
if (_offset == value)
return;
_paintOffset = value;
markNeedsPaint();
if (attached)
_offset.removeListener(markNeedsPaint);
_offset = value;
if (attached)
_offset.addListener(markNeedsPaint);
markNeedsLayout();
}
bool get _isMultiline => maxLines > 1;
Axis get _viewportAxis => _isMultiline ? Axis.vertical : Axis.horizontal;
Offset get _paintOffset {
switch (_viewportAxis) {
case Axis.horizontal:
return new Offset(-offset.pixels, 0.0);
case Axis.vertical:
return new Offset(0.0, -offset.pixels);
}
return null;
}
double get _viewportExtent {
assert(hasSize);
switch (_viewportAxis) {
case Axis.horizontal:
return size.width;
case Axis.vertical:
return size.height;
}
return null;
}
double _getMaxScrollExtent(Size contentSize) {
assert(hasSize);
switch (_viewportAxis) {
case Axis.horizontal:
return math.max(0.0, contentSize.width - size.width);
case Axis.vertical:
return math.max(0.0, contentSize.height - size.height);
}
return null;
}
bool _hasVisualOverflow = false;
/// Returns the global coordinates of the endpoints of the given selection.
///
/// If the selection is collapsed (and therefore occupies a single point), the
......@@ -187,17 +226,17 @@ class RenderEditable extends RenderBox {
// clean at this point.
_textPainter.layout(maxWidth: _maxContentWidth);
Offset offset = _paintOffset;
final Offset paintOffset = _paintOffset;
if (selection.isCollapsed) {
// TODO(mpcomplete): This doesn't work well at an RTL/LTR boundary.
Offset caretOffset = _textPainter.getOffsetForCaret(selection.extent, _caretPrototype);
Point start = new Point(0.0, _preferredLineHeight) + caretOffset + offset;
final Offset caretOffset = _textPainter.getOffsetForCaret(selection.extent, _caretPrototype);
final Point start = new Point(0.0, _preferredLineHeight) + caretOffset + paintOffset;
return <TextSelectionPoint>[new TextSelectionPoint(localToGlobal(start), null)];
} else {
List<ui.TextBox> boxes = _textPainter.getBoxesForSelection(selection);
Point start = new Point(boxes.first.start, boxes.first.bottom) + offset;
Point end = new Point(boxes.last.end, boxes.last.bottom) + offset;
final List<ui.TextBox> boxes = _textPainter.getBoxesForSelection(selection);
final Point start = new Point(boxes.first.start, boxes.first.bottom) + paintOffset;
final Point end = new Point(boxes.last.end, boxes.last.bottom) + paintOffset;
return <TextSelectionPoint>[
new TextSelectionPoint(localToGlobal(start), boxes.first.direction),
new TextSelectionPoint(localToGlobal(end), boxes.last.direction),
......@@ -207,26 +246,24 @@ class RenderEditable extends RenderBox {
/// Returns the position in the text for the given global coordinate.
TextPosition getPositionForPoint(Point globalPosition) {
globalPosition += -paintOffset;
globalPosition += -_paintOffset;
return _textPainter.getPositionForOffset(globalToLocal(globalPosition).toOffset());
}
/// Returns the Rect in local coordinates for the caret at the given text
/// position.
Rect getLocalRectForCaret(TextPosition caretPosition) {
Offset caretOffset = _textPainter.getOffsetForCaret(caretPosition, _caretPrototype);
final Offset caretOffset = _textPainter.getOffsetForCaret(caretPosition, _caretPrototype);
// This rect is the same as _caretPrototype but without the vertical padding.
return new Rect.fromLTWH(0.0, 0.0, _kCaretWidth, _preferredLineHeight).shift(caretOffset + _paintOffset);
}
Size _contentSize;
double get _preferredLineHeight => _textPainter.preferredLineHeight;
double get _maxContentWidth {
return _maxLines > 1 ?
constraints.maxWidth - (_kCaretGap + _kCaretWidth) :
double.INFINITY;
if (_maxLines > 1)
return constraints.maxWidth - (_kCaretGap + _kCaretWidth);
return double.INFINITY;
}
@override
......@@ -257,15 +294,15 @@ class RenderEditable extends RenderBox {
Point _lastTapDownPosition;
Point _longPressPosition;
void _handleTapDown(TapDownDetails details) {
_lastTapDownPosition = details.globalPosition + -paintOffset;
_lastTapDownPosition = details.globalPosition + -_paintOffset;
}
void _handleTap() {
assert(_lastTapDownPosition != null);
final Point global = _lastTapDownPosition;
final Point globalPosition = _lastTapDownPosition;
_lastTapDownPosition = null;
if (onSelectionChanged != null) {
TextPosition position = _textPainter.getPositionForOffset(globalToLocal(global).toOffset());
TextPosition position = _textPainter.getPositionForOffset(globalToLocal(globalPosition).toOffset());
onSelectionChanged(new TextSelection.fromPosition(position), this, false);
}
}
......@@ -277,16 +314,16 @@ class RenderEditable extends RenderBox {
}
void _handleLongPress() {
final Point global = _longPressPosition;
final Point globalPosition = _longPressPosition;
_longPressPosition = null;
if (onSelectionChanged != null) {
TextPosition position = _textPainter.getPositionForOffset(globalToLocal(global).toOffset());
final TextPosition position = _textPainter.getPositionForOffset(globalToLocal(globalPosition).toOffset());
onSelectionChanged(_selectWordAtOffset(position), this, true);
}
}
TextSelection _selectWordAtOffset(TextPosition position) {
TextRange word = _textPainter.getWordBoundary(position);
final TextRange word = _textPainter.getWordBoundary(position);
// When long-pressing past the end of the text, we want a collapsed cursor.
if (position.offset >= word.end)
return new TextSelection.fromPosition(position);
......@@ -297,41 +334,34 @@ class RenderEditable extends RenderBox {
@override
void performLayout() {
Size oldSize = hasSize ? size : null;
_caretPrototype = new Rect.fromLTWH(0.0, _kCaretHeightOffset, _kCaretWidth, _preferredLineHeight - 2.0 * _kCaretHeightOffset);
_selectionRects = null;
_textPainter.layout(maxWidth: _maxContentWidth);
size = new Size(constraints.maxWidth, constraints.constrainHeight(
_textPainter.height.clamp(_preferredLineHeight, _preferredLineHeight * _maxLines)
));
Size contentSize = new Size(_textPainter.width + _kCaretGap + _kCaretWidth, _textPainter.height);
assert(_selection != null);
Rect caretRect = getLocalRectForCaret(_selection.extent);
if (onPaintOffsetUpdateNeeded != null && (size != oldSize || contentSize != _contentSize || !_withinBounds(caretRect)))
onPaintOffsetUpdateNeeded(new ViewportDimensions(containerSize: size, contentSize: contentSize), caretRect);
_contentSize = contentSize;
}
bool _withinBounds(Rect caretRect) {
Rect bounds = new Rect.fromLTWH(0.0, 0.0, size.width, size.height);
return (bounds.contains(caretRect.topLeft) && bounds.contains(caretRect.bottomRight));
final Size contentSize = new Size(_textPainter.width + _kCaretGap + _kCaretWidth, _textPainter.height);
final double _maxScrollExtent = _getMaxScrollExtent(contentSize);
_hasVisualOverflow = _maxScrollExtent > 0.0;
offset.applyViewportDimension(_viewportExtent);
offset.applyContentDimensions(0.0, _maxScrollExtent);
}
void _paintCaret(Canvas canvas, Offset effectiveOffset) {
Offset caretOffset = _textPainter.getOffsetForCaret(_selection.extent, _caretPrototype);
Paint paint = new Paint()..color = _cursorColor;
final Offset caretOffset = _textPainter.getOffsetForCaret(_selection.extent, _caretPrototype);
final Paint paint = new Paint()..color = _cursorColor;
canvas.drawRect(_caretPrototype.shift(caretOffset + effectiveOffset), paint);
}
void _paintSelection(Canvas canvas, Offset effectiveOffset) {
assert(_selectionRects != null);
Paint paint = new Paint()..color = _selectionColor;
final Paint paint = new Paint()..color = _selectionColor;
for (ui.TextBox box in _selectionRects)
canvas.drawRect(box.toRect().shift(effectiveOffset), paint);
}
void _paintContents(PaintingContext context, Offset offset) {
Offset effectiveOffset = offset + _paintOffset;
final Offset effectiveOffset = offset + _paintOffset;
if (_selection != null) {
if (_selection.isCollapsed && _showCursor && cursorColor != null) {
......@@ -345,8 +375,6 @@ class RenderEditable extends RenderBox {
_textPainter.paint(context.canvas, effectiveOffset);
}
bool get _hasVisualOverflow => _contentSize.width > size.width;
@override
void paint(PaintingContext context, Offset offset) {
if (_hasVisualOverflow)
......@@ -357,4 +385,24 @@ class RenderEditable extends RenderBox {
@override
Rect describeApproximatePaintClip(RenderObject child) => _hasVisualOverflow ? Point.origin & size : null;
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('cursorColor: $_cursorColor');
description.add('showCursor: $_showCursor');
description.add('maxLines: $_maxLines');
description.add('selectionColor: $_selectionColor');
description.add('textScaleFactor: $textScaleFactor');
description.add('selection: $_selection');
description.add('offset: $_offset');
}
@override
String debugDescribeChildren(String prefix) {
return '$prefix \u2558\u2550\u2566\u2550\u2550 text \u2550\u2550\u2550\n'
'${text.toString("$prefix \u2551 ")}' // TextSpan includes a newline
'$prefix \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n'
'$prefix\n';
}
}
......@@ -5,14 +5,15 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart' show RenderEditable, SelectionChangedHandler, RenderEditablePaintOffsetNeededCallback;
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'basic.dart';
import 'focus.dart';
import 'framework.dart';
import 'media_query.dart';
import 'scroll_behavior.dart';
import 'scroll_controller.dart';
import 'scroll_physics.dart';
import 'scrollable.dart';
import 'text_selection.dart';
......@@ -135,32 +136,33 @@ class InputValue {
/// * [InputField], which adds tap-to-focus and cut, copy, and paste commands.
/// * [TextField], which is a full-featured, material-design text input field
/// with placeholder text, labels, and [Form] integration.
class EditableText extends Scrollable { // ignore: DEPRECATED_MEMBER_USE
class EditableText extends StatefulWidget {
/// Creates a basic text input control.
///
/// The [value] argument must not be null.
EditableText({
Key key,
@required this.value,
this.focusKey,
@required this.focusKey,
this.obscureText: false,
this.style,
this.cursorColor,
@required this.style,
@required this.cursorColor,
this.textScaleFactor,
int maxLines: 1,
this.maxLines: 1,
this.autofocus: false,
this.selectionColor,
this.selectionControls,
@required this.platform,
this.keyboardType,
this.onChanged,
this.onSubmitted
}) : maxLines = maxLines, super(
key: key,
initialScrollOffset: 0.0,
scrollDirection: maxLines > 1 ? Axis.vertical : Axis.horizontal
) {
this.onSubmitted,
}) : super(key: key) {
assert(value != null);
assert(focusKey != null);
assert(obscureText != null);
assert(style != null);
assert(cursorColor != null);
assert(maxLines != null);
assert(autofocus != null);
}
/// The string being displayed in this widget.
......@@ -206,12 +208,6 @@ class EditableText extends Scrollable { // ignore: DEPRECATED_MEMBER_USE
/// Optional delegate for building the text selection handles and toolbar.
final TextSelectionControls selectionControls;
/// The platform whose behavior should be approximated, in particular
/// for scroll physics. (See [ScrollBehavior.platform].)
///
/// Must not be null.
final TargetPlatform platform;
/// The type of keyboard to use for editing the text.
final TextInputType keyboardType;
......@@ -226,7 +222,7 @@ class EditableText extends Scrollable { // ignore: DEPRECATED_MEMBER_USE
}
/// State for a [EditableText].
class EditableTextState extends ScrollableState<EditableText> implements TextInputClient { // ignore: DEPRECATED_MEMBER_USE
class EditableTextState extends State<EditableText> implements TextInputClient {
Timer _cursorTimer;
bool _showCursor = false;
......@@ -234,11 +230,7 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
TextInputConnection _textInputConnection;
TextSelectionOverlay _selectionOverlay;
@override
ExtentScrollBehavior createScrollBehavior() => new BoundedBehavior(platform: config.platform);
@override
BoundedBehavior get scrollBehavior => super.scrollBehavior;
final ScrollController _scrollController = new ScrollController();
@override
void initState() {
......@@ -259,41 +251,17 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
bool get _isMultiline => config.maxLines > 1;
double _contentExtent = 0.0;
double _containerExtent = 0.0;
Offset _handlePaintOffsetUpdateNeeded(ViewportDimensions dimensions, Rect caretRect) {
// We make various state changes here but don't have to do so in a
// setState() callback because we are called during layout and all
// we're updating is the new offset, which we are providing to the
// render object via our return value.
_contentExtent = _isMultiline ?
dimensions.contentSize.height :
dimensions.contentSize.width;
_containerExtent = _isMultiline ?
dimensions.containerSize.height :
dimensions.containerSize.width;
didUpdateScrollBehavior(scrollBehavior.updateExtents(
contentExtent: _contentExtent,
containerExtent: _containerExtent,
// TODO(ianh): We should really only do this when text is added,
// not generally any time the size changes.
scrollOffset: _getScrollOffsetForCaret(caretRect, _containerExtent)
));
updateGestureDetector();
return scrollOffsetToPixelDelta(scrollOffset);
}
// Calculate the new scroll offset so the cursor remains visible.
double _getScrollOffsetForCaret(Rect caretRect, double containerExtent) {
double caretStart = _isMultiline ? caretRect.top : caretRect.left;
double caretEnd = _isMultiline ? caretRect.bottom : caretRect.right;
double newScrollOffset = scrollOffset;
double _getScrollOffsetForCaret(Rect caretRect) {
final double caretStart = _isMultiline ? caretRect.top : caretRect.left;
final double caretEnd = _isMultiline ? caretRect.bottom : caretRect.right;
double scrollOffset = _scrollController.offset;
final double viewportExtent = _scrollController.position.viewportDimension;
if (caretStart < 0.0) // cursor before start of bounds
newScrollOffset += pixelOffsetToScrollOffset(-caretStart);
else if (caretEnd >= containerExtent) // cursor after end of bounds
newScrollOffset += pixelOffsetToScrollOffset(-(caretEnd - containerExtent));
return newScrollOffset;
scrollOffset += caretStart;
else if (caretEnd >= viewportExtent) // cursor after end of bounds
scrollOffset += caretEnd - viewportExtent;
return scrollOffset;
}
// True if the focus was explicitly requested last frame. This ensures we
......@@ -302,8 +270,7 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
void _attachOrDetachKeyboard(bool focused) {
if (focused && !_isAttachedToKeyboard && (_requestingFocus || config.autofocus)) {
_textInputConnection = TextInput.attach(
this, new TextInputConfiguration(inputType: config.keyboardType))
_textInputConnection = TextInput.attach(this, new TextInputConfiguration(inputType: config.keyboardType))
..setEditingState(_getTextEditingStateFromInputValue(_currentValue))
..show();
} else if (!focused) {
......@@ -364,7 +331,7 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
// EditableWidget, not just changes triggered by user gestures.
requestKeyboard();
InputValue newInput = _currentValue.copyWith(selection: selection, composing: TextRange.empty);
final InputValue newInput = _currentValue.copyWith(selection: selection, composing: TextRange.empty);
if (config.onChanged != null)
config.onChanged(newInput);
......@@ -393,14 +360,7 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
assert(!newInput.composing.isValid); // composing range must be empty while selecting
if (config.onChanged != null)
config.onChanged(newInput);
didUpdateScrollBehavior(scrollBehavior.updateExtents(
// TODO(mpcomplete): should just be able to pass
// scrollBehavior.containerExtent here (and remove the member var), but
// scrollBehavior gets re-created too often, and is sometimes
// uninitialized here. Investigate if this is a bug.
scrollOffset: _getScrollOffsetForCaret(caretRect, _containerExtent)
));
_scrollController.jumpTo(_getScrollOffsetForCaret(caretRect));
}
/// Whether the blinking cursor is actually visible at this precise moment
......@@ -429,9 +389,12 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
_textInputConnection.close();
_textInputConnection = null;
}
assert(!_isAttachedToKeyboard);
if (_cursorTimer != null)
_stopCursorTimer();
assert(_cursorTimer == null);
_selectionOverlay?.dispose();
_selectionOverlay = null;
super.dispose();
}
......@@ -442,11 +405,7 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
}
@override
Widget buildContent(BuildContext context) {
assert(config.style != null);
assert(config.focusKey != null);
assert(config.cursorColor != null);
Widget build(BuildContext context) {
bool focused = Focus.at(config.focusKey.currentContext);
_attachOrDetachKeyboard(focused);
......@@ -464,20 +423,24 @@ class EditableTextState extends ScrollableState<EditableText> implements TextInp
}
}
return new ClipRect(
child: new _Editable(
value: _currentValue,
style: config.style,
cursorColor: config.cursorColor,
showCursor: _showCursor,
maxLines: config.maxLines,
selectionColor: config.selectionColor,
textScaleFactor: config.textScaleFactor ?? MediaQuery.of(context).textScaleFactor,
obscureText: config.obscureText,
onSelectionChanged: _handleSelectionChanged,
paintOffset: scrollOffsetToPixelDelta(scrollOffset),
onPaintOffsetUpdateNeeded: _handlePaintOffsetUpdateNeeded
)
return new Scrollable2(
axisDirection: _isMultiline ? AxisDirection.down : AxisDirection.right,
controller: _scrollController,
physics: const ClampingScrollPhysics(),
viewportBuilder: (BuildContext context, ViewportOffset offset) {
return new _Editable(
value: _currentValue,
style: config.style,
cursorColor: config.cursorColor,
showCursor: _showCursor,
maxLines: config.maxLines,
selectionColor: config.selectionColor,
textScaleFactor: config.textScaleFactor ?? MediaQuery.of(context).textScaleFactor,
obscureText: config.obscureText,
offset: offset,
onSelectionChanged: _handleSelectionChanged,
);
},
);
}
}
......@@ -493,9 +456,8 @@ class _Editable extends LeafRenderObjectWidget {
this.selectionColor,
this.textScaleFactor,
this.obscureText,
this.offset,
this.onSelectionChanged,
this.paintOffset,
this.onPaintOffsetUpdateNeeded
}) : super(key: key);
final InputValue value;
......@@ -506,9 +468,8 @@ class _Editable extends LeafRenderObjectWidget {
final Color selectionColor;
final double textScaleFactor;
final bool obscureText;
final ViewportOffset offset;
final SelectionChangedHandler onSelectionChanged;
final Offset paintOffset;
final RenderEditablePaintOffsetNeededCallback onPaintOffsetUpdateNeeded;
@override
RenderEditable createRenderObject(BuildContext context) {
......@@ -520,9 +481,8 @@ class _Editable extends LeafRenderObjectWidget {
selectionColor: selectionColor,
textScaleFactor: textScaleFactor,
selection: value.selection,
offset: offset,
onSelectionChanged: onSelectionChanged,
paintOffset: paintOffset,
onPaintOffsetUpdateNeeded: onPaintOffsetUpdateNeeded
);
}
......@@ -536,9 +496,8 @@ class _Editable extends LeafRenderObjectWidget {
..selectionColor = selectionColor
..textScaleFactor = textScaleFactor
..selection = value.selection
..onSelectionChanged = onSelectionChanged
..paintOffset = paintOffset
..onPaintOffsetUpdateNeeded = onPaintOffsetUpdateNeeded;
..offset = offset
..onSelectionChanged = onSelectionChanged;
}
TextSpan get _styledTextSpan {
......
......@@ -184,13 +184,13 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
@override
bool get isRepaintBoundary => true;
double get _effectiveExtent {
double get _viewportExtent {
assert(hasSize);
switch (axis) {
case Axis.vertical:
return size.height;
case Axis.horizontal:
return size.width;
case Axis.vertical:
return size.height;
}
return null;
}
......@@ -265,7 +265,7 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
size = constraints.constrain(child.size);
}
offset.applyViewportDimension(_effectiveExtent);
offset.applyViewportDimension(_viewportExtent);
offset.applyContentDimensions(_minScrollExtent, _maxScrollExtent);
}
......
......@@ -581,7 +581,6 @@ void main() {
expect(inputValue.text, cutValue);
}, skip: Platform.isMacOS); // Skip due to https://github.com/flutter/flutter/issues/6961
testWidgets('Can scroll multiline input', (WidgetTester tester) async {
GlobalKey inputKey = new GlobalKey();
InputValue inputValue = InputValue.empty;
......@@ -640,6 +639,7 @@ void main() {
// Now the first line is scrolled up, and the fourth line is visible.
Point newFirstPos = textOffsetToPosition(tester, kFourLines.indexOf('First'));
Point newFourthPos = textOffsetToPosition(tester, kFourLines.indexOf('Fourth'));
expect(newFirstPos.y, lessThan(firstPos.y));
expect(inputBox.hitTest(new HitTestResult(), position: inputBox.globalToLocal(newFirstPos)), isFalse);
expect(inputBox.hitTest(new HitTestResult(), position: inputBox.globalToLocal(newFourthPos)), isTrue);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment