dazedviper
dazedviper

Reputation: 1022

Changing background color of a TextView when clicked

In some apps, such as Plaid or even the Chrome Browser, some portions of the text are underlined to convey the fact that they are a clickable link that will open a browser window or a new tab. When these links are clicked, the whole text's background color changes to that of the underline color. I've tried looking at Plaid's source to replicate this effect, without success. What I'm trying to accomplish is this effect:

enter image description here

Upvotes: 4

Views: 1013

Answers (2)

SuperFrog
SuperFrog

Reputation: 7674

I think this part of the code creates this effect:

https://github.com/nickbutcher/plaid/blob/61d59644d5ae9e373f93cef10e0438c50e2eea6d/app/src/main/java/io/plaidapp/util/LinkTouchMovementMethod.java

It's actually based on this question:

Change the text color of a single ClickableSpan when pressed without affecting other ClickableSpans in the same TextView

public class LinkTouchMovementMethod extends LinkMovementMethod {


private static LinkTouchMovementMethod instance;
private TouchableUrlSpan pressedSpan;

public static MovementMethod getInstance() {
    if (instance == null)
        instance = new LinkTouchMovementMethod();

    return instance;
}

@Override
public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) {
    boolean handled = false;
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        pressedSpan = getPressedSpan(textView, spannable, event);
        if (pressedSpan != null) {
            pressedSpan.setPressed(true);
            Selection.setSelection(spannable, spannable.getSpanStart(pressedSpan),
                    spannable.getSpanEnd(pressedSpan));
            handled = true;
        }
    } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
        TouchableUrlSpan touchedSpan = getPressedSpan(textView, spannable, event);
        if (pressedSpan != null && touchedSpan != pressedSpan) {
            pressedSpan.setPressed(false);
            pressedSpan = null;
            Selection.removeSelection(spannable);
        }
    } else {
        if (pressedSpan != null) {
            pressedSpan.setPressed(false);
            super.onTouchEvent(textView, spannable, event);
            handled = true;
        }
        pressedSpan = null;
        Selection.removeSelection(spannable);
    }
    return handled;
}

private TouchableUrlSpan 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);

    TouchableUrlSpan[] link = spannable.getSpans(off, off, TouchableUrlSpan.class);
    TouchableUrlSpan touchedSpan = null;
    if (link.length > 0) {
        touchedSpan = link[0];
    }
    return touchedSpan;
}

}

Upvotes: 2

Eliran Kuta
Eliran Kuta

Reputation: 4348

Create an XML resource file in res/drawable/my_background.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
    <shape>
        <solid android:color="#343434" />
    </shape>
</item>
</selector>

And set it to your TextView as Background like

  <TextView
    android:id="@+id/tvMytv"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/my_background" />

Upvotes: 2

Related Questions