@@ -16,7 +16,7 @@ object EnhancedMovementMethod : ArrowKeyMovementMethod() {
1616 override fun onTouchEvent (widget : TextView , text : Spannable , event : MotionEvent ): Boolean {
1717 val action = event.action
1818
19- if (action == MotionEvent .ACTION_UP || action == MotionEvent . ACTION_DOWN ) {
19+ if (action == MotionEvent .ACTION_UP ) {
2020 var x = event.x.toInt()
2121 var y = event.y.toInt()
2222
@@ -26,13 +26,11 @@ object EnhancedMovementMethod : ArrowKeyMovementMethod() {
2626 x + = widget.scrollX
2727 y + = widget.scrollY
2828
29+ if (x < 0 ) return true
30+
2931 val layout = widget.layout
3032 val line = layout.getLineForVertical(y)
31- var off = layout.getOffsetForHorizontal(line, x.toFloat())
32-
33- if (text.length > off) {
34- off++
35- }
33+ val off = layout.getOffsetForHorizontal(line, x.toFloat())
3634
3735 // get the character's position. This may be the left or the right edge of the character so, find the
3836 // other edge by inspecting nearby characters (if they exist)
@@ -43,17 +41,42 @@ object EnhancedMovementMethod : ArrowKeyMovementMethod() {
4341 val lineRect = Rect ()
4442 layout.getLineBounds(line, lineRect)
4543
46- if (((x in charPrevX.. charX) || (x in charX.. charNextX))
47- && y >= lineRect.top && y <= lineRect.bottom) {
48- val link = text.getSpans(off, off, ClickableSpan ::class .java).firstOrNull()
44+ val clickedWithinLineHeight = y >= lineRect.top && y <= lineRect.bottom
45+ val clickedOnSpanToTheLeftOfCursor = x in charPrevX.. charX
46+ val clickedOnSpanToTheRightOfCursor = x in charX.. charNextX
47+
48+ val clickedOnSpan = clickedWithinLineHeight &&
49+ (clickedOnSpanToTheLeftOfCursor || clickedOnSpanToTheRightOfCursor)
50+
51+ val clickedSpanBordersAnotherOne = (text.getSpans(off, off, ClickableSpan ::class .java).size == 1 &&
52+ text.getSpans(off + 1 , off + 1 , ClickableSpan ::class .java).isNotEmpty())
53+
54+ val isClickedSpanAmbiguous = text.getSpans(off, off, ClickableSpan ::class .java).size > 1
4955
50- // Only react to AztecMediaClickableSpan and UnknownClickableSpan; not to regular links.
51- if (link != null && (link is AztecMediaClickableSpan || link is UnknownClickableSpan )) {
52- if (action == MotionEvent .ACTION_UP ) {
53- link.onClick(widget)
56+ val failedToPinpointClickedSpan = (isClickedSpanAmbiguous || clickedSpanBordersAnotherOne)
57+ && ! clickedOnSpanToTheLeftOfCursor && ! clickedOnSpanToTheRightOfCursor
58+
59+ var link: ClickableSpan ? = null
60+
61+ if (clickedOnSpan) {
62+ if (isClickedSpanAmbiguous) {
63+ if (clickedOnSpanToTheLeftOfCursor) {
64+ link = text.getSpans(off, off, ClickableSpan ::class .java)[0 ]
65+ } else if (clickedOnSpanToTheRightOfCursor) {
66+ link = text.getSpans(off, off, ClickableSpan ::class .java)[1 ]
5467 }
55- return true
68+ } else {
69+ link = text.getSpans(off, off, ClickableSpan ::class .java).firstOrNull()
70+ }
71+ } else if (failedToPinpointClickedSpan) {
72+ link = text.getSpans(off, off, ClickableSpan ::class .java).firstOrNull { text.getSpanStart(it) == off }
73+ }
74+
75+ if (link != null && (link is AztecMediaClickableSpan || link is UnknownClickableSpan )) {
76+ if (action == MotionEvent .ACTION_UP ) {
77+ link.onClick(widget)
5678 }
79+ return true
5780 }
5881 }
5982
0 commit comments