Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linkified TextView consumes touch events #14

Closed
rubengees opened this issue May 13, 2018 · 8 comments
Closed

Linkified TextView consumes touch events #14

rubengees opened this issue May 13, 2018 · 8 comments

Comments

@rubengees
Copy link

rubengees commented May 13, 2018

One of my apps requires a click listener on the TextView and/or parent views (e.g. in a RecyclerView) and also has linkified text in it.

After the MovementMethod is applied, the click listeners do not work anymore. This is an age-old bug, but there are workarounds.

A similar library solves this by having a custom TextView that intercepts onTouch events and handles them differently when a touch on a link is in progress or not.

Maybe a similar approach can be introduced to this library? Currently i am using this gross hack:

// BetterLinkTextView.kt

override fun onTouchEvent(event: MotionEvent?): Boolean {
    super.onTouchEvent(event)
    
    if (movementMethod is BetterLinkMovementMethod) {
        val span = getTag(R.id.bettermovementmethod_highlight_background_span)

        return span != null && (text as? Spannable)?.getSpanStart(span) ?: -1 >= 0
    }

    return false
}

This could be improved by having a first class api if a click is in progress and/or by having a TextView doing this in the library.

Thanks for looking into this!

@saket
Copy link
Owner

saket commented May 14, 2018

Oh yea this is really annoying. I'm doing something less gross in my app:

class SomeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

  private val bodyTextView: TextView
  
  @SuppressLint("ClickableViewAccessibility")
  fun forwardTouchEventsToBackground(linkMovementMethod: BetterLinkMovementMethod) {
    // Bug workaround: TextView with clickable spans consume all touch events. Manually
    // transfer them to the parent so that the background touch indicator shows up +
    // click listener works.
    bodyTextView!!.setOnTouchListener { o, event ->
      val handledByMovementMethod = linkMovementMethod.onTouchEvent(bodyTextView, bodyTextView.text as Spannable, event)
      handledByMovementMethod || itemView.onTouchEvent(event)
    }
  }
}

Maybe we can generalize this solution without explicitly knowing about the existence of BetterLinkMovementMethod?

@noties
Copy link

noties commented Jun 5, 2018

Hey @saket !

Maybe BetterLinkMovementMethod can capture click event and call TextView#performClick?

@saket
Copy link
Owner

saket commented Jul 10, 2018

Oh hey @noties. Sorry i just saw your message. I was busy attending droidcon Berlin and roaming around Europe. Capturing TextView's click events sounds like an interesting idea. I will explore this, thanks!

@rayliverified
Copy link

Thank you so much! The problem of how to pass up textview clicks to the parent has been troubling people for years. @saket your solution works great :)

@saket
Copy link
Owner

saket commented Sep 26, 2018

Closing this issue. Please feel free to re-open it for more questions.

@saket saket closed this as completed Sep 26, 2018
@samthesamman
Copy link

Was there a solution to passing touch events to parent views when the user taps somewhere on the textview that isn't a link?

@saket
Copy link
Owner

saket commented Mar 9, 2019

@chankruse does the solution in this comment not work? #14 (comment)

@JunbinDeng
Copy link

@saket solution works great. It would be better to write in a TextView.

public class LinkifyTextView extends TextView {

    public LinkifyTextView(Context context) {
        super(context);
    }

    public LinkifyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LinkifyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public LinkifyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final MovementMethod movementMethod = getMovementMethod();
        final CharSequence text = getText();
        if (movementMethod instanceof BetterLinkMovementMethod && text instanceof Spannable) {
            return movementMethod.onTouchEvent(this, (Spannable) text, event) || super.onTouchEvent(event);
        }
        return super.dispatchTouchEvent(event);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants