diff options
author | Maryam Garrett <mkamvar@google.com> | 2009-12-01 14:40:03 -0500 |
---|---|---|
committer | Maryam Garrett <mkamvar@google.com> | 2009-12-03 14:20:53 -0500 |
commit | ce08379e22609415971ece6ba3417d6d3fd338d2 (patch) | |
tree | 9e129c4ceb8428949e977cfa80b38293b7037faa /core/java/android/text/method | |
parent | 51e45ff0d53ce299be316e14e48cdd3e3a51d0b0 (diff) | |
download | frameworks_base-ce08379e22609415971ece6ba3417d6d3fd338d2.zip frameworks_base-ce08379e22609415971ece6ba3417d6d3fd338d2.tar.gz frameworks_base-ce08379e22609415971ece6ba3417d6d3fd338d2.tar.bz2 |
Improves the touch-based text selection UI in text boxes.
With this change, when a user is in "text select" mode, they
can swipe any part of the text. This changes the behavior of
the touch-based select in 2 ways (behavior for cursor-based
select remains the same):
1. You can now indicate where your select will start. Before
this change, the select always started at the last cursor
position.
2. Selection will respect word boundaries. Before this
change the selection would be character to character. Since
users don't have a fine grain level of control over touch
events, this would often lead to incomplete selections.
Diffstat (limited to 'core/java/android/text/method')
-rw-r--r-- | core/java/android/text/method/ArrowKeyMovementMethod.java | 125 |
1 files changed, 93 insertions, 32 deletions
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index ab33cb3..789172f 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -54,7 +54,7 @@ implements MovementMethod Selection.setSelection(buffer, 0); return true; } else { - return Selection.moveUp(buffer, layout); + return Selection.moveUp(buffer, layout); } } } @@ -80,7 +80,7 @@ implements MovementMethod Selection.setSelection(buffer, buffer.length()); return true; } else { - return Selection.moveDown(buffer, layout); + return Selection.moveDown(buffer, layout); } } } @@ -133,6 +133,35 @@ implements MovementMethod } } + private int getOffset(int x, int y, TextView widget){ + // Converts the absolute X,Y coordinates to the character offset for the + // character whose position is closest to the specified + // horizontal position. + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + + // Clamp the position to inside of the view. + if (x < 0) { + x = 0; + } else if (x >= (widget.getWidth()-widget.getTotalPaddingRight())) { + x = widget.getWidth()-widget.getTotalPaddingRight() - 1; + } + if (y < 0) { + y = 0; + } else if (y >= (widget.getHeight()-widget.getTotalPaddingBottom())) { + y = widget.getHeight()-widget.getTotalPaddingBottom() - 1; + } + + x += widget.getScrollX(); + y += widget.getScrollY(); + + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + + int offset = layout.getOffsetForHorizontal(line, x); + return offset; + } + public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { if (executeDown(widget, buffer, keyCode)) { MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); @@ -196,12 +225,12 @@ implements MovementMethod } return false; } - + public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) { return false; } - + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int initialScrollX = -1, initialScrollY = -1; @@ -209,11 +238,63 @@ implements MovementMethod initialScrollX = Touch.getInitialScrollX(widget, buffer); initialScrollY = Touch.getInitialScrollY(widget, buffer); } - + boolean handled = Touch.onTouchEvent(widget, buffer, event); if (widget.isFocused() && !widget.didTouchFocusSelect()) { - if (event.getAction() == MotionEvent.ACTION_UP) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + boolean cap = (MetaKeyKeyListener.getMetaState(buffer, + KeyEvent.META_SHIFT_ON) == 1) || + (MetaKeyKeyListener.getMetaState(buffer, + MetaKeyKeyListener.META_SELECTING) != 0); + if (cap) { + int x = (int) event.getX(); + int y = (int) event.getY(); + int offset = getOffset(x, y, widget); + + buffer.setSpan(LAST_TAP_DOWN, offset, offset, + Spannable.SPAN_POINT_POINT); + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE ) { + boolean cap = (MetaKeyKeyListener.getMetaState(buffer, + KeyEvent.META_SHIFT_ON) == 1) || + (MetaKeyKeyListener.getMetaState(buffer, + MetaKeyKeyListener.META_SELECTING) != 0); + + if (cap) { + // Update selection as we're moving the selection area. + + // Get the current touch position + int x = (int) event.getX(); + int y = (int) event.getY(); + int offset = getOffset(x, y, widget); + + // Get the last down touch position (the position at which the + // user started the selection) + int lastDownOffset = buffer.getSpanStart(LAST_TAP_DOWN); + + // Compute the selection boundries + int spanstart; + int spanend; + if (offset >= lastDownOffset) { + // expand to from word start of the original tap to new word + // end, since we are selecting "forwards" + spanstart = findWordStart(buffer, lastDownOffset); + spanend = findWordEnd(buffer, offset); + } else { + // Expand to from new word start to word end of the original + // tap since we are selecting "backwards". + // The spanend will always need to be associated with the touch + // up position, so that refining the selection with the + // trackball will work as expected. + spanstart = findWordEnd(buffer, lastDownOffset); + spanend = findWordStart(buffer, offset); + } + + Selection.setSelection(buffer, spanstart, spanend); + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { // If we have scrolled, then the up shouldn't move the cursor, // but we do need to make sure the cursor is still visible at // the current scroll offset to avoid the scroll jumping later @@ -223,35 +304,13 @@ implements MovementMethod widget.moveCursorToVisibleOffset(); return true; } - + int x = (int) event.getX(); int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - // Clamp the position to inside of the view. - if (x < 0) { - x = 0; - } else if (x >= (widget.getWidth()-widget.getTotalPaddingRight())) { - x = widget.getWidth()-widget.getTotalPaddingRight() - 1; - } - if (y < 0) { - y = 0; - } else if (y >= (widget.getHeight()-widget.getTotalPaddingBottom())) { - y = widget.getHeight()-widget.getTotalPaddingBottom() - 1; - } - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - - int off = layout.getOffsetForHorizontal(line, x); + int off = getOffset(x, y, widget); // XXX should do the same adjust for x as we do for the line. - + boolean cap = (MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) || (MetaKeyKeyListener.getMetaState(buffer, @@ -278,7 +337,7 @@ implements MovementMethod } if (cap) { - Selection.extendSelection(buffer, off); + buffer.removeSpan(LAST_TAP_DOWN); } else if (doubletap) { Selection.setSelection(buffer, findWordStart(buffer, off), @@ -395,5 +454,7 @@ implements MovementMethod return sInstance; } + + private static final Object LAST_TAP_DOWN = new Object(); private static ArrowKeyMovementMethod sInstance; } |