複数の ClickableSpan を含む TextView があります。ClickableSpan が押されたときに、テキストの色を変更したいと考えています。
TextViewのtextColorLink属性としてカラー状態リストを設定しようとしましたが、これは次のような結果をもたらすため、望みどおりの結果は得られません。全てユーザーがクリックすると色が変わるスパンどこでもTextView で。
興味深いことに、textColorHighlight を使用して背景色を変更すると、期待どおりに動作します。スパンをクリックすると、そのスパンの背景色のみが変更され、TextView 内の他の場所をクリックしても何も起こりません。
また、ClickableSpans と同じ境界で ForegroundColorSpans を設定し、上記と同じカラー状態リストをカラー リソースとして渡すことも試みました。 これも機能しません。 スパンは、カラー状態リストで常にデフォルト状態の色を保持し、押された状態になることはありません。
誰かこれをどうやってやるのか知っていますか?
私が使用したカラー状態リストは次のとおりです。
<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>
ベストアンサー1
ついに私が望んでいたことをすべて実現するソリューションを見つけました。この答え。
これは、タッチ イベント (MotionEvent.ACTION_DOWN) の開始時にスパンが押されたものとしてマークされ、タッチが終了するかタッチ位置がスパン外に移動するとマークが解除される、私が修正した LinkMovementMethod です。
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());
これは、LinkTouchMovementMethod によって設定された押下状態に基づいて描画状態を編集する、修正された ClickableSpan です。(リンクから下線も削除されます)
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);
}
}