Commit be865e1e authored by Hixie's avatar Hixie

SizeObserver crusade: RawInputLine

parent 76b9d8d1
......@@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
import 'basic_types.dart';
import 'box.dart';
import 'object.dart';
import 'viewport.dart';
const _kCaretGap = 1.0; // pixels
const _kCaretHeightOffset = 2.0; // pixels
......@@ -24,9 +25,9 @@ class RenderEditableLine extends RenderBox {
bool showCursor: false,
Color selectionColor,
TextSelection selection,
Offset paintOffset: Offset.zero,
this.onSelectionChanged,
this.onContentSizeChanged
Offset paintOffset: Offset.zero,
this.onPaintOffsetUpdateNeeded
}) : _textPainter = new TextPainter(text),
_cursorColor = cursorColor,
_showCursor = showCursor,
......@@ -45,8 +46,8 @@ class RenderEditableLine extends RenderBox {
..onTapCancel = _handleTapCancel;
}
ValueChanged<Size> onContentSizeChanged;
ValueChanged<TextSelection> onSelectionChanged;
ViewportDimensionsChangeCallback onPaintOffsetUpdateNeeded;
/// The text to display
TextSpan get text => _textPainter.text;
......@@ -201,16 +202,15 @@ class RenderEditableLine extends RenderBox {
Rect _caretPrototype;
void performLayout() {
Size oldSize = hasSize ? size : null;
size = new Size(constraints.maxWidth, constraints.constrainHeight(_preferredHeight));
_caretPrototype = new Rect.fromLTWH(0.0, _kCaretHeightOffset, _kCaretWidth, size.height - 2.0 * _kCaretHeightOffset);
_selectionRects = null;
_layoutText(new BoxConstraints(minHeight: constraints.minHeight, maxHeight: constraints.maxHeight));
Size contentSize = new Size(_textPainter.width + _kCaretGap + _kCaretWidth, _textPainter.height);
if (_contentSize != contentSize) {
_contentSize = contentSize;
if (onContentSizeChanged != null)
onContentSizeChanged(_contentSize);
}
if (onPaintOffsetUpdateNeeded != null && (size != oldSize || contentSize != _contentSize))
onPaintOffsetUpdateNeeded(new ViewportDimensions(containerSize: size, contentSize: contentSize));
_contentSize = contentSize;
}
void _paintCaret(Canvas canvas, Offset effectiveOffset) {
......
......@@ -189,9 +189,6 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
Timer _cursorTimer;
bool _showCursor = false;
double _contentWidth = 0.0;
double _containerWidth = 0.0;
_KeyboardClientImpl _keyboardClient;
KeyboardHandle _keyboardHandle;
......@@ -218,24 +215,28 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
bool get _isAttachedToKeyboard => _keyboardHandle != null && _keyboardHandle.attached;
void _handleContainerSizeChanged(Size newSize) {
_containerWidth = newSize.width;
_updateScrollBehavior();
}
void _handleContentSizeChanged(Size newSize) {
_contentWidth = newSize.width;
_updateScrollBehavior();
}
double _contentWidth = 0.0;
double _containerWidth = 0.0;
void _updateScrollBehavior() {
// 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.
Offset _handlePaintOffsetUpdateNeeded(ViewportDimensions dimensions) {
// 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.
_containerWidth = dimensions.containerSize.width;
_contentWidth = dimensions.contentSize.width;
scrollTo(scrollBehavior.updateExtents(
contentExtent: _contentWidth,
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) {
......@@ -327,19 +328,16 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
else if (_cursorTimer != null && (!focused || !config.value.selection.isCollapsed))
_stopCursorTimer();
return new SizeObserver(
onSizeChanged: _handleContainerSizeChanged,
child: new _EditableLineWidget(
value: config.value,
style: config.style,
cursorColor: config.cursorColor,
showCursor: _showCursor,
selectionColor: config.selectionColor,
hideText: config.hideText,
onContentSizeChanged: _handleContentSizeChanged,
onSelectionChanged: _handleSelectionChanged,
paintOffset: new Offset(-scrollOffset, 0.0)
)
return new _EditableLineWidget(
value: config.value,
style: config.style,
cursorColor: config.cursorColor,
showCursor: _showCursor,
selectionColor: config.selectionColor,
hideText: config.hideText,
onSelectionChanged: _handleSelectionChanged,
paintOffset: scrollOffsetToPixelDelta(scrollOffset),
onPaintOffsetUpdateNeeded: _handlePaintOffsetUpdateNeeded
);
}
}
......@@ -353,9 +351,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
this.showCursor,
this.selectionColor,
this.hideText,
this.onContentSizeChanged,
this.onSelectionChanged,
this.paintOffset
this.paintOffset,
this.onPaintOffsetUpdateNeeded
}) : super(key: key);
final InputValue value;
......@@ -364,9 +362,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
final bool showCursor;
final Color selectionColor;
final bool hideText;
final ValueChanged<Size> onContentSizeChanged;
final ValueChanged<TextSelection> onSelectionChanged;
final Offset paintOffset;
final ViewportDimensionsChangeCallback onPaintOffsetUpdateNeeded;
RenderEditableLine createRenderObject() {
return new RenderEditableLine(
......@@ -375,9 +373,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
showCursor: showCursor,
selectionColor: selectionColor,
selection: value.selection,
onContentSizeChanged: onContentSizeChanged,
onSelectionChanged: onSelectionChanged,
paintOffset: paintOffset
paintOffset: paintOffset,
onPaintOffsetUpdateNeeded: onPaintOffsetUpdateNeeded
);
}
......@@ -389,9 +387,9 @@ class _EditableLineWidget extends LeafRenderObjectWidget {
..showCursor = showCursor
..selectionColor = selectionColor
..selection = value.selection
..onContentSizeChanged = onContentSizeChanged
..onSelectionChanged = onSelectionChanged
..paintOffset = paintOffset;
..paintOffset = paintOffset
..onPaintOffsetUpdateNeeded = onPaintOffsetUpdateNeeded;
}
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
/// 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 }) {
if (newScrollOffset == _scrollOffset)
return new Future.value();
......@@ -390,6 +394,7 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return new Future.value();
}
assert(duration > Duration.ZERO);
return _animateTo(newScrollOffset, duration, curve);
}
......
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