android - 按下时更改单个 ClickableSpan 的文本颜色,而不影响同一 TextView 中的其他 ClickableSpan

标签 android layout textview textcolor

我有一个 TextView,里面有多个 ClickableSpan。当按下 ClickableSpan 时,我希望它改变其文本的颜色。

我尝试将颜色状态列表设置为 TextView 的 textColorLink 属性。这不会产生预期的结果,因为当用户在 TextView 上单击 anywhere 时,这会导致 所有跨度改变颜色。

有趣的是,使用 textColorHighlight 更改背景颜色可以按预期工作:单击 span 只会更改该 span 的背景颜色,而单击 TextView 中的其他任何地方都不会执行任何操作。

我还尝试将 ForegroundColorSpans 设置为与 ClickableSpans 相同的边界,在其中我传递与上面相同的颜色状态列表作为颜色资源。这也不起作用。 span 始终保持颜色状态列表中默认状态的颜色,永远不会进入按下状态。

有人知道怎么做吗?

这是我使用的颜色状态列表:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true" android:color="@color/pressed_color"/>
  <item android:color="@color/normal_color"/>
</selector>

最佳答案

我终于找到了一个可以满足我所有需求的解决方案。它基于 this answer .

这是我修改后的 LinkMovementMethod,它在触摸事件 (MotionEvent.ACTION_DOWN) 开始时将跨度标记为按下,并在触摸结束或触摸位置移出跨度时取消标记。

public class LinkTouchMovementMethod extends LinkMovementMethod {
    private TouchableSpan mPressedSpan;

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

    private TouchableSpan getPressedSpan(
            TextView textView,
            Spannable spannable,
            MotionEvent event) {

            int x = (int) event.getX() - textView.getTotalPaddingLeft() + textView.getScrollX();
            int y = (int) event.getY() - textView.getTotalPaddingTop() + textView.getScrollY();

            Layout layout = textView.getLayout();
            int position = layout.getOffsetForHorizontal(layout.getLineForVertical(y), x);

            TouchableSpan[] link = spannable.getSpans(position, position, TouchableSpan.class);
            TouchableSpan touchedSpan = null;
            if (link.length > 0 && positionWithinTag(position, spannable, link[0])) {
                touchedSpan = link[0];
            }

            return touchedSpan;
        }

        private boolean positionWithinTag(int position, Spannable spannable, Object tag) {
            return position >= spannable.getSpanStart(tag) && position <= spannable.getSpanEnd(tag);
        }
    }

这需要像这样应用于 TextView:

    yourTextView.setMovementMethod(new LinkTouchMovementMethod());

这是修改后的 ClickableSpan,它根据 LinkTouchMovementMethod 设置的按下状态编辑绘制状态:(它还删除了链接中的下划线)

public abstract class TouchableSpan extends ClickableSpan {
    private boolean mIsPressed;
    private int mPressedBackgroundColor;
    private int mNormalTextColor;
    private int mPressedTextColor;

    public TouchableSpan(int normalTextColor, int pressedTextColor, int pressedBackgroundColor) {
        mNormalTextColor = normalTextColor;
        mPressedTextColor = pressedTextColor;
        mPressedBackgroundColor = pressedBackgroundColor;
    }

    public void setPressed(boolean isSelected) {
        mIsPressed = isSelected;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setColor(mIsPressed ? mPressedTextColor : mNormalTextColor);
        ds.bgColor = mIsPressed ? mPressedBackgroundColor : 0xffeeeeee;
        ds.setUnderlineText(false);
    }
}

关于android - 按下时更改单个 ClickableSpan 的文本颜色,而不影响同一 TextView 中的其他 ClickableSpan,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20856105/

相关文章:

android - 如何控制Android接近传感器?

Android - 状态栏阻止全屏

python - 更新-刷新布局

java - 如何使用 URI (Android) 创建目录?

android - Camera Preview 需要一些时间来重新绘制 Orientation Change

java - 仅当不直接扩展 RecyclerView 时才会出现 InflateException

android - 我可以改变 clickablespan 的外观和感觉吗

CSS 网格全高

java - 如何设置TextView边框的阴影

android - 在 TextView 中缩进项目符号列表