Merge pull request #2207 from Hixie/size-obs-5
SizeObserver crusade: RawInputLine
This commit is contained in:
commit
e843d9d0af
@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
|
|||||||
import 'basic_types.dart';
|
import 'basic_types.dart';
|
||||||
import 'box.dart';
|
import 'box.dart';
|
||||||
import 'object.dart';
|
import 'object.dart';
|
||||||
|
import 'viewport.dart';
|
||||||
|
|
||||||
const _kCaretGap = 1.0; // pixels
|
const _kCaretGap = 1.0; // pixels
|
||||||
const _kCaretHeightOffset = 2.0; // pixels
|
const _kCaretHeightOffset = 2.0; // pixels
|
||||||
@ -24,9 +25,9 @@ class RenderEditableLine extends RenderBox {
|
|||||||
bool showCursor: false,
|
bool showCursor: false,
|
||||||
Color selectionColor,
|
Color selectionColor,
|
||||||
TextSelection selection,
|
TextSelection selection,
|
||||||
Offset paintOffset: Offset.zero,
|
|
||||||
this.onSelectionChanged,
|
this.onSelectionChanged,
|
||||||
this.onContentSizeChanged
|
Offset paintOffset: Offset.zero,
|
||||||
|
this.onPaintOffsetUpdateNeeded
|
||||||
}) : _textPainter = new TextPainter(text),
|
}) : _textPainter = new TextPainter(text),
|
||||||
_cursorColor = cursorColor,
|
_cursorColor = cursorColor,
|
||||||
_showCursor = showCursor,
|
_showCursor = showCursor,
|
||||||
@ -45,8 +46,8 @@ class RenderEditableLine extends RenderBox {
|
|||||||
..onTapCancel = _handleTapCancel;
|
..onTapCancel = _handleTapCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueChanged<Size> onContentSizeChanged;
|
|
||||||
ValueChanged<TextSelection> onSelectionChanged;
|
ValueChanged<TextSelection> onSelectionChanged;
|
||||||
|
ViewportDimensionsChangeCallback onPaintOffsetUpdateNeeded;
|
||||||
|
|
||||||
/// The text to display
|
/// The text to display
|
||||||
TextSpan get text => _textPainter.text;
|
TextSpan get text => _textPainter.text;
|
||||||
@ -201,16 +202,15 @@ class RenderEditableLine extends RenderBox {
|
|||||||
Rect _caretPrototype;
|
Rect _caretPrototype;
|
||||||
|
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
|
Size oldSize = hasSize ? size : null;
|
||||||
size = new Size(constraints.maxWidth, constraints.constrainHeight(_preferredHeight));
|
size = new Size(constraints.maxWidth, constraints.constrainHeight(_preferredHeight));
|
||||||
_caretPrototype = new Rect.fromLTWH(0.0, _kCaretHeightOffset, _kCaretWidth, size.height - 2.0 * _kCaretHeightOffset);
|
_caretPrototype = new Rect.fromLTWH(0.0, _kCaretHeightOffset, _kCaretWidth, size.height - 2.0 * _kCaretHeightOffset);
|
||||||
_selectionRects = null;
|
_selectionRects = null;
|
||||||
_layoutText(new BoxConstraints(minHeight: constraints.minHeight, maxHeight: constraints.maxHeight));
|
_layoutText(new BoxConstraints(minHeight: constraints.minHeight, maxHeight: constraints.maxHeight));
|
||||||
Size contentSize = new Size(_textPainter.width + _kCaretGap + _kCaretWidth, _textPainter.height);
|
Size contentSize = new Size(_textPainter.width + _kCaretGap + _kCaretWidth, _textPainter.height);
|
||||||
if (_contentSize != contentSize) {
|
if (onPaintOffsetUpdateNeeded != null && (size != oldSize || contentSize != _contentSize))
|
||||||
|
onPaintOffsetUpdateNeeded(new ViewportDimensions(containerSize: size, contentSize: contentSize));
|
||||||
_contentSize = contentSize;
|
_contentSize = contentSize;
|
||||||
if (onContentSizeChanged != null)
|
|
||||||
onContentSizeChanged(_contentSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _paintCaret(Canvas canvas, Offset effectiveOffset) {
|
void _paintCaret(Canvas canvas, Offset effectiveOffset) {
|
||||||
|
@ -189,9 +189,6 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
|
|||||||
Timer _cursorTimer;
|
Timer _cursorTimer;
|
||||||
bool _showCursor = false;
|
bool _showCursor = false;
|
||||||
|
|
||||||
double _contentWidth = 0.0;
|
|
||||||
double _containerWidth = 0.0;
|
|
||||||
|
|
||||||
_KeyboardClientImpl _keyboardClient;
|
_KeyboardClientImpl _keyboardClient;
|
||||||
KeyboardHandle _keyboardHandle;
|
KeyboardHandle _keyboardHandle;
|
||||||
|
|
||||||
@ -218,24 +215,28 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
|
|||||||
|
|
||||||
bool get _isAttachedToKeyboard => _keyboardHandle != null && _keyboardHandle.attached;
|
bool get _isAttachedToKeyboard => _keyboardHandle != null && _keyboardHandle.attached;
|
||||||
|
|
||||||
void _handleContainerSizeChanged(Size newSize) {
|
double _contentWidth = 0.0;
|
||||||
_containerWidth = newSize.width;
|
double _containerWidth = 0.0;
|
||||||
_updateScrollBehavior();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleContentSizeChanged(Size newSize) {
|
Offset _handlePaintOffsetUpdateNeeded(ViewportDimensions dimensions) {
|
||||||
_contentWidth = newSize.width;
|
// We make various state changes here but don't have to do so in a
|
||||||
_updateScrollBehavior();
|
// 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.
|
||||||
void _updateScrollBehavior() {
|
_containerWidth = dimensions.containerSize.width;
|
||||||
// Set the scroll offset to match the content width so that the cursor
|
_contentWidth = dimensions.contentSize.width;
|
||||||
// (which is always at the end of the text) will be visible.
|
|
||||||
scrollTo(scrollBehavior.updateExtents(
|
scrollTo(scrollBehavior.updateExtents(
|
||||||
contentExtent: _contentWidth,
|
contentExtent: _contentWidth,
|
||||||
containerExtent: _containerWidth,
|
containerExtent: _containerWidth,
|
||||||
scrollOffset: _contentWidth
|
// Set the scroll offset to match the content width so that the
|
||||||
|
// cursor (which is always at the end of the text) will be
|
||||||
|
// visible.
|
||||||
|
// TODO(ianh): We should really only do this when text is added,
|
||||||
|
// not generally any time the size changes.
|
||||||
|
scrollOffset: pixelOffsetToScrollOffset(-_contentWidth)
|
||||||
));
|
));
|
||||||
|
updateGestureDetector();
|
||||||
|
return scrollOffsetToPixelDelta(scrollOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _attachOrDetachKeyboard(bool focused) {
|
void _attachOrDetachKeyboard(bool focused) {
|
||||||
@ -327,19 +328,16 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
|
|||||||
else if (_cursorTimer != null && (!focused || !config.value.selection.isCollapsed))
|
else if (_cursorTimer != null && (!focused || !config.value.selection.isCollapsed))
|
||||||
_stopCursorTimer();
|
_stopCursorTimer();
|
||||||
|
|
||||||
return new SizeObserver(
|
return new _EditableLineWidget(
|
||||||
onSizeChanged: _handleContainerSizeChanged,
|
|
||||||
child: new _EditableLineWidget(
|
|
||||||
value: config.value,
|
value: config.value,
|
||||||
style: config.style,
|
style: config.style,
|
||||||
cursorColor: config.cursorColor,
|
cursorColor: config.cursorColor,
|
||||||
showCursor: _showCursor,
|
showCursor: _showCursor,
|
||||||
selectionColor: config.selectionColor,
|
selectionColor: config.selectionColor,
|
||||||
hideText: config.hideText,
|
hideText: config.hideText,
|
||||||
onContentSizeChanged: _handleContentSizeChanged,
|
|
||||||
onSelectionChanged: _handleSelectionChanged,
|
onSelectionChanged: _handleSelectionChanged,
|
||||||
paintOffset: new Offset(-scrollOffset, 0.0)
|
paintOffset: scrollOffsetToPixelDelta(scrollOffset),
|
||||||
)
|
onPaintOffsetUpdateNeeded: _handlePaintOffsetUpdateNeeded
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,9 +351,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
|
|||||||
this.showCursor,
|
this.showCursor,
|
||||||
this.selectionColor,
|
this.selectionColor,
|
||||||
this.hideText,
|
this.hideText,
|
||||||
this.onContentSizeChanged,
|
|
||||||
this.onSelectionChanged,
|
this.onSelectionChanged,
|
||||||
this.paintOffset
|
this.paintOffset,
|
||||||
|
this.onPaintOffsetUpdateNeeded
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final InputValue value;
|
final InputValue value;
|
||||||
@ -364,9 +362,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
|
|||||||
final bool showCursor;
|
final bool showCursor;
|
||||||
final Color selectionColor;
|
final Color selectionColor;
|
||||||
final bool hideText;
|
final bool hideText;
|
||||||
final ValueChanged<Size> onContentSizeChanged;
|
|
||||||
final ValueChanged<TextSelection> onSelectionChanged;
|
final ValueChanged<TextSelection> onSelectionChanged;
|
||||||
final Offset paintOffset;
|
final Offset paintOffset;
|
||||||
|
final ViewportDimensionsChangeCallback onPaintOffsetUpdateNeeded;
|
||||||
|
|
||||||
RenderEditableLine createRenderObject() {
|
RenderEditableLine createRenderObject() {
|
||||||
return new RenderEditableLine(
|
return new RenderEditableLine(
|
||||||
@ -375,9 +373,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
|
|||||||
showCursor: showCursor,
|
showCursor: showCursor,
|
||||||
selectionColor: selectionColor,
|
selectionColor: selectionColor,
|
||||||
selection: value.selection,
|
selection: value.selection,
|
||||||
onContentSizeChanged: onContentSizeChanged,
|
|
||||||
onSelectionChanged: onSelectionChanged,
|
onSelectionChanged: onSelectionChanged,
|
||||||
paintOffset: paintOffset
|
paintOffset: paintOffset,
|
||||||
|
onPaintOffsetUpdateNeeded: onPaintOffsetUpdateNeeded
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,9 +387,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
|
|||||||
..showCursor = showCursor
|
..showCursor = showCursor
|
||||||
..selectionColor = selectionColor
|
..selectionColor = selectionColor
|
||||||
..selection = value.selection
|
..selection = value.selection
|
||||||
..onContentSizeChanged = onContentSizeChanged
|
|
||||||
..onSelectionChanged = onSelectionChanged
|
..onSelectionChanged = onSelectionChanged
|
||||||
..paintOffset = paintOffset;
|
..paintOffset = paintOffset
|
||||||
|
..onPaintOffsetUpdateNeeded = onPaintOffsetUpdateNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextSpan get _styledTextSpan {
|
TextSpan get _styledTextSpan {
|
||||||
|
@ -380,6 +380,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
|
|||||||
///
|
///
|
||||||
/// If a non-null [duration] is provided, the widget will animate to the new
|
/// If a non-null [duration] is provided, the widget will animate to the new
|
||||||
/// scroll offset over the given duration with the given curve.
|
/// scroll offset over the given duration with the given curve.
|
||||||
|
///
|
||||||
|
/// This function does not accept a zero duration. To jump-scroll to
|
||||||
|
/// the new offset, do not provide a duration, rather than providing
|
||||||
|
/// a zero duration.
|
||||||
Future scrollTo(double newScrollOffset, { Duration duration, Curve curve: Curves.ease }) {
|
Future scrollTo(double newScrollOffset, { Duration duration, Curve curve: Curves.ease }) {
|
||||||
if (newScrollOffset == _scrollOffset)
|
if (newScrollOffset == _scrollOffset)
|
||||||
return new Future.value();
|
return new Future.value();
|
||||||
@ -390,6 +394,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
|
|||||||
return new Future.value();
|
return new Future.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(duration > Duration.ZERO);
|
||||||
return _animateTo(newScrollOffset, duration, curve);
|
return _animateTo(newScrollOffset, duration, curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user