下面列出了android.text.Layout#getOffsetForHorizontal ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private int pointToPosition(int x, int y) {
x -= getCompoundPaddingLeft();
y -= getExtendedPaddingTop();
x += getScrollX();
y += getScrollY();
Layout layout = getLayout();
if (layout == null) {
return -1;
}
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
return off;
}
TouchableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= textView.getTotalPaddingLeft();
y -= textView.getTotalPaddingTop();
x += textView.getScrollX();
y += textView.getScrollY();
Layout layout = textView.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
TouchableSpan[] link = spannable.getSpans(off, off, TouchableSpan.class);
TouchableSpan touchedSpan = null;
if (link.length > 0) {
touchedSpan = link[0];
}
return touchedSpan;
}
private String getLinkText(final TextView widget, final Spannable buffer, final MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
return buffer.subSequence(buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0])).toString();
}
return buffer.toString();
}
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP) {
return super.onTouchEvent(widget, buffer, event);
}
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0) {
onLinkClick(link[0].getURL());
}
return true;
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
// Let the parent or grandparent of TextView to handles click aciton.
// Otherwise click effect like ripple will not work, and if touch area
// do not contain a url, the TextView will still get MotionEvent.
// onTouchEven must be called with MotionEvent.ACTION_DOWN for each touch
// action on it, so we analyze touched url here.
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mCurrentSpan = null;
if (getText() instanceof Spanned) {
// Get this code from android.text.method.LinkMovementMethod.
// Work fine !
int x = (int) event.getX();
int y = (int) event.getY();
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
x += getScrollX();
y += getScrollY();
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
Object[] spans = ((Spanned)getText()).getSpans(off, off, Object.class);
for (Object span : spans) {
if (Utilities.contain(SUPPORTED_SPAN_TYPE, span.getClass())) {
mCurrentSpan = span;
break;
}
}
}
}
return super.onTouchEvent(event);
}
@Override
public boolean onTouchEvent(TextView widget,
Spannable buffer, MotionEvent event ) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP)
{
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0)
{
// display the license
displayLicense();
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
private int getOffsetForHorizontal(TextView widget,
MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
return layout.getOffsetForHorizontal(line, x);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean ret = false;
CharSequence text = ((TextView) v).getText();
Spannable stext = Spannable.Factory.getInstance().newSpannable(text);
TextView widget = (TextView) v;
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = stext.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
}
ret = true;
}
}
return ret;
}
private <T> T[] findSpansToClickSingle(Layout layout, Spanned spanned, Class<T> type, int x, int y) {
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
T[] spans = spanned.getSpans(off, off, type);
if (spans != null) {
for (int i = 0; i < spans.length; i++) {
int end = spanned.getSpanEnd(spans[i]);
if (off >= end) {
spans[i] = null;
}
}
}
return spans;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
if(System.currentTimeMillis() - lastClickTime < CLICK_DELAY){
link[0].onClick(widget);
}
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
lastClickTime = System.currentTimeMillis();
}
return true;
} else {
Selection.removeSelection(buffer);
}
}
return super.onTouchEvent(widget, buffer, event);
}
/**
* @param layout
* @param x 相对自己ev.getX()
* @param y
* @return
*/
public int extractWordCurOff(Layout layout, int x, int y) {
int line;
line = layout
.getLineForVertical(getScrollY() + y - 10);
int curOff = layout.getOffsetForHorizontal(line, x);
return curOff;
}
private CustomClickableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= textView.getTotalPaddingLeft();
y -= textView.getTotalPaddingTop();
x += textView.getScrollX();
y += textView.getScrollY();
Layout layout = textView.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
CustomClickableSpan[] link = spannable.getSpans(off, off, CustomClickableSpan.class);
CustomClickableSpan touchedSpan = null;
if (link.length == 2) {
touchedSpan = link[0];
CustomClickableSpan tempSpan = link[1];
touchedSpan.setOnTextClickListener(touchedSpan.getOnTextClickListener() != null ? touchedSpan.getOnTextClickListener() : tempSpan.getOnTextClickListener());
touchedSpan.setOnTextLongClickListener(touchedSpan.getOnTextLongClickListener() != null ? touchedSpan.getOnTextLongClickListener() : tempSpan.getOnTextLongClickListener());
} else if (link.length == 1){
touchedSpan = link[0];
}
return touchedSpan;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
LongClickCopySpan longClickCopySpan[] = buffer.getSpans(off, off, LongClickCopySpan.class);
if (longClickCopySpan.length != 0) {
LongClickCopySpan aSingleSpan = longClickCopySpan[0];
if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer, buffer.getSpanStart(aSingleSpan),
buffer.getSpanEnd(aSingleSpan));
aSingleSpan.setHighlighted(true,
ContextCompat.getColor(widget.getContext(), R.color.touch_highlight));
} else {
Selection.removeSelection(buffer);
aSingleSpan.setHighlighted(false, Color.TRANSPARENT);
}
this.currentSpan = aSingleSpan;
this.widget = widget;
return gestureDetector.onTouchEvent(event);
}
} else if (action == MotionEvent.ACTION_CANCEL) {
// Remove Selections.
LongClickCopySpan[] spans = buffer.getSpans(Selection.getSelectionStart(buffer),
Selection.getSelectionEnd(buffer), LongClickCopySpan.class);
for (LongClickCopySpan aSpan : spans) {
aSpan.setHighlighted(false, Color.TRANSPARENT);
}
Selection.removeSelection(buffer);
return gestureDetector.onTouchEvent(event);
}
return super.onTouchEvent(widget, buffer, event);
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_DOWN
|| action == MotionEvent.ACTION_MOVE
|| action == MotionEvent.ACTION_CANCEL) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] clickableLinks = buffer.getSpans(off, off, ClickableSpan.class);
LongPressClickableSpan[] longPressClickableLinks = buffer.getSpans(off, off, LongPressClickableSpan.class);
switch (action) {
case MotionEvent.ACTION_UP:
if (clickableLinks.length != 0) {
if (!mIsLongPressed) {
clickableLinks[0].onClick(widget);
}
mIsLongPressed = false;
mHandler.removeMessages(LONG_PRESS);
}
return true;
case MotionEvent.ACTION_DOWN:
if (clickableLinks.length != 0) {
if (longPressClickableLinks.length == 0) {
Selection.setSelection(buffer,
buffer.getSpanStart(clickableLinks[0]),
buffer.getSpanEnd(clickableLinks[0]));
} else {
mX = (int) event.getX();
mY = (int) event.getY();
mHandler.removeMessages(LONG_PRESS);
mHandler.sendMessageAtTime(Message.obtain(mHandler, LONG_PRESS, new Object[]{longPressClickableLinks[0], widget}),
event.getDownTime() + ViewConfiguration.getLongPressTimeout());
}
}
return true;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - mX) > 50
&& Math.abs(event.getX() - mY) > 50) {
mHandler.removeMessages(LONG_PRESS);
}
return super.onTouchEvent(widget, buffer, event);
case MotionEvent.ACTION_CANCEL:
mHandler.removeMessages(LONG_PRESS);
return super.onTouchEvent(widget, buffer, event);
}
if (clickableLinks.length == 0) {
Selection.removeSelection(buffer);
}
}
return super.onTouchEvent(widget, buffer, event);
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
LongClickableSpan[] link = buffer.getSpans(off, off, LongClickableSpan.class);
if (link.length != 0) {
long currTime = System.currentTimeMillis();
LongClickableSpan l = link[0];
int ls = buffer.getSpanStart(l);
int le = buffer.getSpanEnd(l);
// 判断点击的点是否在Image范围内
ClickableImageSpan[] is = buffer.getSpans(ls, le, ClickableImageSpan.class);
if (is.length > 0) {
if (!is[0].clicked(x)) {
Selection.removeSelection(buffer);
return false;
}
} else if (off < layout.getOffsetToLeftOf(ls) || off > layout.getOffsetToLeftOf(le + 1)) {
// 判断点击位置是否在链接范围内
Selection.removeSelection(buffer);
return false;
}
if (action == MotionEvent.ACTION_UP) {
// 如果按下时间超过500毫秒,触发长按事件
if (currTime - lastTime > MIN_INTERVAL) {
if (!l.onLongClick(widget)) {
// onLongClick返回false代表事件未处理,交由onClick处理
l.onClick(widget);
}
} else {
l.onClick(widget);
}
} else {
Selection.setSelection(buffer,
ls, le);
}
lastTime = currTime;
return true;
} else {
Selection.removeSelection(buffer);
return false;
}
}
return super.onTouchEvent(widget, buffer, event);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!(v instanceof TextView)) {
return false;
}
TextView widget = (TextView) v;
//widget.getText() is SpannedString
Spannable buffer = Spannable.Factory.getInstance().newSpannable(widget.getText());
int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);
if (links.length != 0) {
if (action == MotionEvent.ACTION_UP) {
removeLongClick(v);
links[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer, buffer.getSpanStart(links[0]), buffer.getSpanEnd(links[0]));
checkForLongClick(v, 0);
}
return true;
} else {
Selection.removeSelection(buffer);
}
} else if (action == MotionEvent.ACTION_CANCEL) {
removeLongClick(v);
}
return false;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
if (widget instanceof TextViewFixTouchConsume) {
((TextViewFixTouchConsume) widget).mlinkHit = true;
}
return true;
} else {
Selection.removeSelection(buffer);
Touch.onTouchEvent(widget, buffer, event);
return false;
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off,
ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
if (widget instanceof TextViewFixTouchConsume) {
((TextViewFixTouchConsume) widget).linkHit = true;
}
return true;
} else {
Selection.removeSelection(buffer);
Touch.onTouchEvent(widget, buffer, event);
return false;
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
/**
* http://stackoverflow.com/a/17246463/2299887
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean ret = false;
CharSequence text = getText();
Spannable stext = Spannable.Factory.getInstance().newSpannable(text);
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
x += getScrollX();
y += getScrollY();
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = stext.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
long currentClickTime = System.currentTimeMillis();
long elapsedTime = currentClickTime - mLastClickTime;
mLastClickTime = currentClickTime;
if (elapsedTime > MIN_CLICK_INTERVAL) {
try {
link[0].onClick(this);
} catch (Exception e) {
UIUtils.toast("发生错误 : " + e.getMessage());
}
}
}
ret = true;
}
}
return ret;
}
@Override
public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
Layout layout = widget.getLayout();
if (layout == null) {
return super.onTouchEvent(widget, buffer, event);
}
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
MyURLSpan[] link = buffer.getSpans(off, off, MyURLSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
if (!mHasPerformedLongPress) {
link[0].onClick(widget);
}
pressed = false;
lastEvent = new float[2];
} else {
pressed = true;
lastEvent[0] = event.getX();
lastEvent[1] = event.getY();
checkForLongClick(link, widget);
}
return true;
}
} else if (action == MotionEvent.ACTION_MOVE) {
float[] position = {
event.getX(), event.getY()
};
// int slop =
// ViewConfiguration.get(widget.getContext()).getScaledTouchSlop();
int slop = 6;
float xInstance = Math.abs(lastEvent[0] - position[0]);
float yInstance = Math.abs(lastEvent[1] - position[1]);
double instance = Math.sqrt(Math.hypot(xInstance, yInstance));
if (instance > slop) {
pressed = false;
}
} else if (action == MotionEvent.ACTION_CANCEL) {
pressed = false;
lastEvent = new float[2];
} else {
pressed = false;
lastEvent = new float[2];
}
return super.onTouchEvent(widget, buffer, event);
}