Comment faire pour qu'une partie du texte d'une case à cocher soit cliquable?

j'essaie de créer un lien dans le texte adjacent de ma boîte de texte. Ce lien n'est cependant pas une URL, mais doit agir comme un bouton pour que je puisse effectuer quelques tâches dans l'événement onItemClick. En gros, je connecte ceci à une vue qui montre notre accord de licence D'utilisateur final (codé en dur).

Comment puis-je accomplir?

Merci d'avance.

24
demandé sur PaulG 2011-11-18 19:13:59

7 réponses

il y a en fait une solution élégante, en utilisant CheckBox et simple TextView . Avec une combinaison de TextView.setClickable() , Filtre d'Intention, et TextView.setMovementMethod() .

vous avez vue principale (ici, je l'ai appelé 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());
    }
}

principal.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>

activité.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>

et le dernier morceau de codes qui colle tout, le 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>

Voici les explications:

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 vous permettra de cliquer sur textView . Mais pas le lien HREF. Pour ce faire, vous devrez utiliser setMovementMethod() et réglez LinkMovementMethod .

après cela, vous devez attraper L'URL. J'ai fait cela en utilisant intent-filter dans AndroidManifest.xml

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

attraper une commande de VUE et il ne filtre des URL commençant par id.web.freelancer.example.TCActivity://

voici le paquet pour que vous l'essayiez et voici le dépôt github . Espérons que cela a aidé

24
répondu ariefbayu 2015-06-18 06:34:36

le code suivant a fonctionné pour moi sur KitKat. Je suis encore à tester sur les versions ci-dessous D'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());
34
répondu Gopinath 2014-02-11 12:05:25

vous pouvez vouloir que seulement une partie du texte soit un lien cliquable, tandis que le reste de la case à cocher se comporte comme d'habitude, i.e. vous pouvez cliquer sur l'autre texte pour basculer l'état.

vous pouvez configurer votre case comme suit:

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());
10
répondu Daniel Schuler 2018-06-12 19:06:37

j'ai eu le même problème et je voulais avoir plus d'un lien cliquable dans le texte d'une case à cocher sans perdre la possibilité de cliquer n'importe où dans le texte (où il n'y a pas D'URL) pour sélectionner/désélectionner la case à cocher.

la différence avec les autres réponses à cette question Est qu'avec cette solution vous pouvez avoir plusieurs liens cliquables dans le texte de case à cocher et ces liens ne doivent pas être à la fin du texte.

la disposition semble semblable à celui dans ariefbayu 'S réponse:

<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>

j'ai maintenant réglé le texte par programmation. Le texte que je veux afficher est:

"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>"

comme il contient HTML, je le convertis d'abord en une portée. Pour rendre les liens cliquables, j'ai en outre défini la méthode de mouvement du TextView à LinkMovementMethod:

mTosTextView = (TextView) findViewById(R.id.tosTextView);
mTosTextView.setText(Html.fromHtml(getString(R.string.TOSInfo)));
mTosTextView.setMovementMethod(LinkMovementMethod.getInstance());

et voici la partie la plus délicate. Jusqu'à présent, la Case à cocher ne pas obtenir sélectionné en appuyant sur la fenêtre TextView. Pour y arriver, j'ai ajouté un gestionnaire tactile à 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;
    }
});

Enfin, comme vous l'avez probablement remarqué, il n'y a pas de méthode getOffsetForPosition(...) . Si vous visez API Niveau 14+, Vous pouvez simplement utiliser getOffsetForPosition() , comme indiqué par Dheeraj V. S. . Comme je cible le niveau D'API 8+, j'ai utilisé une implémentation que j'ai trouvé ici: déterminer quel mot est cliqué dans un android textview .

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
répondu Flo 2017-05-23 12:34:39

créer un CheckBox sans texte et ajouter deux TextView s à côté. La première est une vue non cliquable avec un texte comme "j'ai lu et j'accepte le". Le second est un cliquable voir avec un texte comme "Termes et CONDITIONS". Placez le TextView côte à côte sans aucune marge. Avis de l'espace supplémentaire à la fin de la première vue naturel, l'alignement du texte. De cette façon, vous pouvez style les deux textes comme vous le souhaitez.

exemple de code 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>



Puis Ajouter un handler onClick() dans le code. Voilá.

public class SignUpActivity extends Activity {

    public void onClick(View v) {
        ...
    }  
}
3
répondu Jarno Argillander 2011-11-18 15:47:43

si vous cherchez une solution avec L'URL, je vous suggère d'utiliser la solution de suivi. Avec CheckBox et 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"; et R.string.terms_and_conds = id de la ressource avec la cliquables chaîne.

0
répondu validcat 2013-02-05 15:27:10

Je n'ai pas aimé la solution avec la case à cocher + textView car votre vue personnalisée va étendre un groupe de vue et non une case à cocher vous forçant ainsi à envelopper le comportement de case à cocher.

il était important pour moi que la case à cocher personnalisée puisse être utilisée en xml exactement comme une normale.

le comportement acceptable pour moi était que cette case à cocher ne sera activée que lorsque vous appuyez sur sa case et non sur son texte.

donc j'ai prolongé CheckBox, et afin d'atteindre ce comportement, j'ai joué avec le mécanisme touch entier, le code complet est ci-dessous, et une explication juste après pour tous ceux qui aiment à savoir comment cela fonctionne.

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();
}
}

il relaie sur le fait que la méthode performClick est appelée en interne par le mécanisme TextView que CheckBox étend, le ClickableSpan est également appelé par le mécanisme TextView. donc ce qui se passe, c'est que lorsque vous touchez le texte de votre case à cocher il appellera les deux.

donc ce que j'ai fait est de détecter si le clic était dans la zone de texte, si c'est le cas, nous désactiverons le perfomClick désactivant ainsi la bascule. mais la portée cliquable sera quand même appelée.

Utilisation:

vous avez encore besoin d'ajouter une portée cliquable et setMovementMethod comme avant, tout comme un TextView régulier.

0
répondu ndori 2016-06-28 11:31:35