У меня была та же проблема, и я хотел, чтобы в тексте флажка было более одной кликабельной ссылки без потери возможности щелкнуть в любом месте текста (где нет URL), чтобы установить / снять флажок.
Отличие от других ответов на этот вопрос заключается в том, что с этим решением вы можете иметь несколько кликабельных ссылок в тексте флажка, и эти ссылки не обязательно должны быть в конце текста.
Макет выглядит так же, как в ariefbayu :
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<CheckBox
android:id="@+id/tosCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:checked="false" />
<TextView
android:id="@+id/tosTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tosCheckBox"
android:layout_centerVertical="true"
android:clickable="true" />
</RelativeLayout>
Теперь я установил текст программно. Текст, который я хочу отобразить:
"I have read and accepted the <a href='https://www.anyurl.com/privacy'>privacy statement</a> and <a href='https://www.anyurl.com/tos'>terms of service.</a>"
Поскольку он содержит HTML, я сначала конвертирую его в Spanned. Чтобы сделать ссылки кликабельными, я дополнительно установил метод перемещения TextView на LinkMovementMethod:
mTosTextView = (TextView) findViewById(R.id.tosTextView);
mTosTextView.setText(Html.fromHtml(getString(R.string.TOSInfo)));
mTosTextView.setMovementMethod(LinkMovementMethod.getInstance());
А вот и более сложная часть. До сих пор CheckBox не выбирается при нажатии TextView. Чтобы добиться этого, я добавил сенсорный обработчик в TextView:
mTosCheckBox = (CheckBox) findViewById(R.id.tosCheckBox);
mTosTextView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
CharSequence text = mTosTextView.getText();
// find out which character was touched
int offset = getOffsetForPosition(mTosTextView, event.getX(), event.getY());
// check if this character contains a URL
URLSpan[] types = ((Spanned)text).getSpans(offset, offset, URLSpan.class);
if (types.length > 0) {
// a link was clicked, so don't handle the event
Log.d("Some tag", "link clicked: " + types[0].getURL());
return false;
}
// no link was touched, so handle the touch to change
// the pressed state of the CheckBox
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTosCheckBox.setPressed(true);
break;
case MotionEvent.ACTION_UP:
mTosCheckBox.setChecked(!mTosCheckBox.isChecked());
mTosCheckBox.setPressed(false);
break;
default:
mTosCheckBox.setPressed(false);
break;
}
return true;
}
});
Наконец, как вы, наверное, заметили, метода getOffsetForPosition(...)
пока нет. Если вы нацелены на уровень API 14+, вы можете просто использовать getOffsetForPosition()
, , как указано Dheeraj V.S. . Поскольку я нацеливаюсь на уровень API 8+, я использовал реализацию, которую нашел здесь: Определение слова, которое нажимается в текстовом представлении Android .
public int getOffsetForPosition(TextView textView, float x, float y) {
if (textView.getLayout() == null) {
return -1;
}
final int line = getLineAtCoordinate(textView, y);
final int offset = getOffsetAtCoordinate(textView, line, x);
return offset;
}
private int getOffsetAtCoordinate(TextView textView2, int line, float x) {
x = convertToLocalHorizontalCoordinate(textView2, x);
return textView2.getLayout().getOffsetForHorizontal(line, x);
}
private float convertToLocalHorizontalCoordinate(TextView textView2, float x) {
x -= textView2.getTotalPaddingLeft();
// Clamp the position to inside of the view.
x = Math.max(0.0f, x);
x = Math.min(textView2.getWidth() - textView2.getTotalPaddingRight() - 1, x);
x += textView2.getScrollX();
return x;
}
private int getLineAtCoordinate(TextView textView2, float y) {
y -= textView2.getTotalPaddingTop();
// Clamp the position to inside of the view.
y = Math.max(0.0f, y);
y = Math.min(textView2.getHeight() - textView2.getTotalPaddingBottom() - 1, y);
y += textView2.getScrollY();
return textView2.getLayout().getLineForVertical((int) y);
}