diff options
-rw-r--r-- | api/current.xml | 41 | ||||
-rw-r--r-- | core/java/android/text/method/ArrowKeyMovementMethod.java | 32 | ||||
-rw-r--r-- | core/java/android/text/method/Touch.java | 22 | ||||
-rw-r--r-- | core/java/android/widget/TextView.java | 56 |
4 files changed, 147 insertions, 4 deletions
diff --git a/api/current.xml b/api/current.xml index dbfa2b9..a68e510 100644 --- a/api/current.xml +++ b/api/current.xml @@ -110598,6 +110598,36 @@ deprecated="not deprecated" visibility="public" > +<method name="getInitialScrollX" + return="int" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="widget" type="android.widget.TextView"> +</parameter> +<parameter name="buffer" type="android.text.Spannable"> +</parameter> +</method> +<method name="getInitialScrollY" + return="int" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="widget" type="android.widget.TextView"> +</parameter> +<parameter name="buffer" type="android.text.Spannable"> +</parameter> +</method> <method name="onTouchEvent" return="boolean" abstract="false" @@ -157343,6 +157373,17 @@ visibility="public" > </method> +<method name="moveCursorToVisibleOffset" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="onBeginBatchEdit" return="void" abstract="false" diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index 17c7a6c..92f6289 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -18,6 +18,7 @@ package android.text.method; import android.util.Log; import android.view.KeyEvent; +import android.graphics.Rect; import android.text.*; import android.widget.TextView; import android.view.View; @@ -202,23 +203,54 @@ implements MovementMethod public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { + int initialScrollX = -1, initialScrollY = -1; + if (event.getAction() == MotionEvent.ACTION_UP) { + 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 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 + // to show it. + if ((initialScrollY >= 0 && initialScrollY != widget.getScrollY()) || + (initialScrollX >= 0 && initialScrollX != widget.getScrollX())) { + 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); + // 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, diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java index 65036ad..f2fb9cb 100644 --- a/core/java/android/text/method/Touch.java +++ b/core/java/android/text/method/Touch.java @@ -21,7 +21,6 @@ import android.text.NoCopySpan; import android.text.Layout.Alignment; import android.text.Spannable; import android.view.MotionEvent; -import android.view.View; import android.view.ViewConfiguration; import android.widget.TextView; @@ -82,8 +81,9 @@ public class Touch { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - buffer.setSpan(new DragState(event.getX(), event.getY()), - 0, 0, Spannable.SPAN_MARK_MARK); + buffer.setSpan(new DragState(event.getX(), event.getY(), + widget.getScrollX(), widget.getScrollY()), + 0, 0, Spannable.SPAN_MARK_MARK); return true; case MotionEvent.ACTION_UP: @@ -142,15 +142,29 @@ public class Touch { return false; } + public static int getInitialScrollX(TextView widget, Spannable buffer) { + DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class); + return ds.length > 0 ? ds[0].mScrollX : -1; + } + + public static int getInitialScrollY(TextView widget, Spannable buffer) { + DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class); + return ds.length > 0 ? ds[0].mScrollY : -1; + } + private static class DragState implements NoCopySpan { public float mX; public float mY; + public int mScrollX; + public int mScrollY; public boolean mFarEnough; public boolean mUsed; - public DragState(float x, float y) { + public DragState(float x, float y, int scrollX, int scrollY) { mX = x; mY = y; + mScrollX = scrollX; + mScrollY = scrollY; } } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 136752b..01b65b6 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5421,6 +5421,62 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return changed; } + /** + * Move the cursor, if needed, so that it is at an offset that is visible + * to the user. This will not move the cursor if it represents more than + * one character (a selection range). This will only work if the + * TextView contains spannable text; otherwise it will do nothing. + */ + public boolean moveCursorToVisibleOffset() { + if (!(mText instanceof Spannable)) { + return false; + } + int start = Selection.getSelectionStart(mText); + int end = Selection.getSelectionEnd(mText); + if (start != end) { + return false; + } + + // First: make sure the line is visible on screen: + + int line = mLayout.getLineForOffset(start); + + final int top = mLayout.getLineTop(line); + final int bottom = mLayout.getLineTop(line+1); + final int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom(); + int vslack = (bottom - top) / 2; + if (vslack > vspace / 4) + vslack = vspace / 4; + final int vs = mScrollY; + + if (top < (vs+vslack)) { + line = mLayout.getLineForVertical(vs+vslack+(bottom-top)); + } else if (bottom > (vspace+vs-vslack)) { + line = mLayout.getLineForVertical(vspace+vs-vslack-(bottom-top)); + } + + // Next: make sure the character is visible on screen: + + final int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(); + final int hs = mScrollX; + final int leftChar = mLayout.getOffsetForHorizontal(line, hs); + final int rightChar = mLayout.getOffsetForHorizontal(line, hspace+hs); + + int newStart = start; + if (newStart < leftChar) { + newStart = leftChar; + } else if (newStart > rightChar) { + newStart = rightChar; + } + + if (newStart != start) { + Selection.setSelection((Spannable)mText, newStart); + return true; + } + + return false; + } + @Override public void computeScroll() { if (mScroller != null) { |