Подтвердить что ты не робот

Как сделать часть текста флажка доступной?

Я пытаюсь создать ссылку в текстовом поле рядом с текстом. Однако эта ссылка не является URL-адресом, но должна действовать как кнопка, чтобы я мог выполнять несколько задач в событии onItemClick. Я в основном подключаю это к представлению, которое показывает наше Лицензионное соглашение с конечным пользователем (жестко закодированное).

Как я могу это сделать?

Спасибо заранее.

4b9b3361

Ответ 1

На самом деле это элегантное решение, используя CheckBox и single TextView. Наряду с комбинациями TextView.setClickable(), Intent Filter и TextView.setMovementMethod().

У вас есть основной вид (здесь я назвал его ClickableTextViewExample):

package id.web.freelancer.example;

import android.app.Activity;
import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.widget.CheckBox;
import android.widget.TextView;

public class ClickableTextViewExampleActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        CheckBox checkbox = (CheckBox)findViewById(R.id.checkBox1);
        TextView textView = (TextView)findViewById(R.id.textView2);

        checkbox.setText("");
        textView.setText(Html.fromHtml("I have read and agree to the " +
                "<a href='id.web.freelancer.example.TCActivity://Kode'>TERMS AND CONDITIONS</a>"));
        textView.setClickable(true);
        textView.setMovementMethod(LinkMovementMethod.getInstance());
    }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <CheckBox
            android:id="@+id/checkBox1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="CheckBox" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView"
            android:clickable="true" />

    </LinearLayout>

</LinearLayout>

TCActivity.java

package id.web.freelancer.example;

import android.app.Activity;
import android.os.Bundle;

public class TCActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tc);
    }

}

tc.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

        <TextView
        android:id="@+id/tcView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Terms and conditions" />


</LinearLayout>

и последний кусок кодов, которые склеивают все это, AndroidManifest.xml:

<activity android:name="TCActivity">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT" />
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="id.web.freelancer.example.TCActivity" />  
    </intent-filter>            
</activity>

Вот, объяснения:

textView.setText(Html.fromHtml("I have read and agree to the " +
                     "<a href='id.web.freelancer.example.TCActivity://Kode'>TERMS AND CONDITIONS</a>"));
textView.setClickable(true);
textView.setMovementMethod(LinkMovementMethod.getInstance());

setClickable позволит вам щелкнуть по TextView. Но не ссылка HREF. Для этого вам нужно будет использовать setMovementMethod() и установить его на LinkMovementMethod.

После этого вам нужно поймать URL. Я сделал это, используя intent-filter в AndroidManifest.xml

<action android:name="android.intent.action.VIEW" />
<data android:scheme="id.web.freelancer.example.TCActivity" />  

Он улавливает команду VIEW и фильтрует только URL-адрес, начинающийся с id.web.freelancer.example.TCActivity://

Здесь пакет для вас попробовать и здесь github хранилище. Надеюсь, что это помогло

Ответ 2

Следующий код работал у меня на KitKat. Я еще не тестировал ниже версии Android.

String checkBoxText = "I agree to all the <a href='http://www.redbus.in/mob/mTerms.aspx' > Terms and Conditions</a>";

checkBoxView.setText(Html.fromHtml(checkBoxText));
checkBoxView.setMovementMethod(LinkMovementMethod.getInstance());

Ответ 3

Вы можете захотеть, чтобы только часть текста была ссылкой на клики, в то время как остальная часть флажка ведет себя как обычно, т.е. Вы можете щелкнуть другой текст, чтобы переключить состояние.

Вы можете настроить свой флажок следующим образом:

CheckBox checkBox = (CheckBox) findViewById(R.id.my_check_box);

ClickableSpan clickableSpan = new ClickableSpan() {
    @Override
    public void onClick(View widget) {
        // Prevent CheckBox state from being toggled when link is clicked
        widget.cancelPendingInputEvents();
        // Do action for link text...
    }
    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        // Show links with underlines (optional)
        ds.setUnderlineText(true);
    }
};

SpannableString linkText = new SpannableString("Link text");
linkText.setSpan(clickableSpan, 0, linkText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
CharSequence cs = TextUtils.expandTemplate(
    "CheckBox text with link: ^1 , and after link", linkText);

checkBox.setText(cs);
// Finally, make links clickable
checkBox.setMovementMethod(LinkMovementMethod.getInstance());

Ответ 4

У меня была такая же проблема, и я хотел иметь несколько ссылок на клики в тексте флажка, не теряя возможности щелкнуть в любом месте текста (где нет 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 VS. Когда я нацелился на уровень 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);
}

Ответ 5

Создайте CheckBox без текста и добавьте два TextView рядом с ним. Первый - это не кликабельный вид с текстом типа "Я прочитал и согласен с". Второй - это интерактивное представление с текстом типа "УСЛОВИЯ И УСЛОВИЯ". Поместите TextView бок о бок без каких-либо ограничений. Обратите внимание на дополнительное пространство в конце первого представления для естественного выравнивания текста. Таким образом, вы можете стилизовать оба текста по своему усмотрению.

Пример кода xml:

<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <CheckBox
        android:id="@+id/terms_check"
        android:text=""
        android:layout_marginLeft="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/terms_text"
        android:layout_toRightOf="@id/terms_check"
        android:text="I have read and agree to the "
        android:layout_marginLeft="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/terms_link"
        android:layout_toRightOf="@id/terms_text"
        android:text="TERMS AND CONDITIONS"
        android:textColor="#00f"
        android:onClick="onClick"
        android:clickable="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>


Затем добавьте обработчик onClick() в код. Вуаля.

public class SignUpActivity extends Activity {

    public void onClick(View v) {
        ...
    }  
}

Ответ 6

Если вы ищете решение с URL-адресом, я предлагаю вам использовать следующее решение. С CheckBox и TextView.

    final TextView tvTerms = (TextView)findViewById(R.id.tvTerms);

    Pattern pattern = Pattern.compile(getString(R.string.terms_and_conds));
    TransformFilter transFilter = new TransformFilter() {
    @Override
    public String transformUrl(Matcher match, String url) {
        return "";
    }}; 
    Linkify.addLinks(tvTerms, pattern, Constants.URL_TERMS_AND_CONDS, null, transFilter);

где URL_TERMS_AND_CONDS = "yourUrl.com"; и R.string.terms_and_conds= id к ресурсу с помощью строки, которая может быть нажата.

Ответ 7

Мне не понравилось решение с checkBox + textView, так как ваше пользовательское представление расширит ViewGroup, а не CheckBox, что заставило вас обернуть поведение CheckBox.

Мне было важно, чтобы пользовательский CheckBox мог использоваться в xml точно так же, как обычный.

Допустимое поведение для меня состояло в том, что этот CheckBox будет только переключаться, когда вы нажимаете на него, а не на нем.

Итак, я расширил CheckBox, и для достижения такого поведения я играл со всем сенсорным механизмом, полный код ниже и объяснение сразу после него для тех, кто любит знать, как это работает.

public class CheckBoxWithLinks extends CheckBox {


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

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

public CheckBoxWithLinks(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
public boolean performClick() {
    if ( !onTextClick)
        return super.performClick();
    return false;
}

private boolean onTextClick = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
    onTextClick = !isLeftDrawableClick(event) && !isRightDrawableClick(event);
    return super.onTouchEvent(event);
}

private boolean isRightDrawableClick(MotionEvent event) {
    return event.getX() >= getRight() - getTotalPaddingRight();
}

private boolean isLeftDrawableClick(MotionEvent event) {
    return event.getX() <= getTotalPaddingLeft();
}
}

он ссылается на то, что метод performClick является внутренним вызовом механизма TextView, который расшифровывается CheckBox, и ClickableSpan также вызывается механизмом TextView. так что случается, что когда вы касаетесь текста CheckBox, он вызывает оба.

Итак, что я сделал, обнаруживает, был ли щелчок в текстовой области, поэтому мы отключим perfomClick, отключив этот переключатель. но кликабельный диапазон по-прежнему будет вызываться.

Использование:

Вам по-прежнему нужно добавить кликабельный диапазон и setMovementMethod, как и раньше, точно так же, как обычный TextView.

Ответ 8

Котлинская версия (через расширение) ответа Даниэля Шулера:

fun CheckBox.addClickableLink(fullText: String, linkText: SpannableString, callback: () -> Unit) {
    val clickableSpan = object : ClickableSpan() {
        override fun onClick(widget: View) {
            widget.cancelPendingInputEvents() // Prevent CheckBox state from being toggled when link is clicked
            callback.invoke()
        }

        override fun updateDrawState(ds: TextPaint) {
            super.updateDrawState(ds)
            ds.isUnderlineText = true // Show links with underlines
        }
    }
    linkText.setSpan(clickableSpan, 0, linkText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    val fullTextWithTemplate = fullText.replace(linkText.toString(), "^1", false)
    val cs = TextUtils.expandTemplate(fullTextWithTemplate, linkText)

    text = cs
    movementMethod = LinkMovementMethod.getInstance() // Make link clickable
}

Использование :

yourCheckBox.addClickableLink(
    fullText = "This link must be clickable",
    linkText = SpannableString("This link")
) {
    // Do whatever you want when onClick()
}