如何使Checkbox文本的一部分可单击?

时间:2021-10-26 22:21:32

I'm trying to create a link in my textbox's adjacent text. This link however is not a URL, but should act as a button so that I can perform a few tasks in the onItemClick event. I'm basically connecting this to a view that shows our End User License Agreement (hard coded).

我正在尝试在文本框的相邻文本中创建一个链接。但是,此链接不是URL,而应充当按钮,以便我可以在onItemClick事件中执行一些任务。我基本上将此连接到显示我们的最终用户许可协议(硬编码)的视图。

How can I accomplish this?

我怎么能做到这一点?

Thanks in advance.

提前致谢。

7 个解决方案

#1


24  

There actually is an elegant solution, using CheckBox and single TextView. Along with a combinations of TextView.setClickable(), Intent Filter, and TextView.setMovementMethod().

实际上有一个优雅的解决方案,使用CheckBox和单个TextView。与TextView.setClickable(),Intent Filter和TextView.setMovementMethod()的组合一起使用。

You have main view (here, I called it ClickableTextViewExample):

你有主视图(这里,我称之为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>

and the final piece of codes that glue it all, the AndroidManifest.xml:

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>

Here comes, the explanations:

来了,解释:

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 will allow you to click on textView. But not the HREF link. To do that, you will have to use setMovementMethod() and set it to LinkMovementMethod.

setClickable将允许您单击textView。但不是HREF链接。为此,您必须使用setMovementMethod()并将其设置为LinkMovementMethod。

After that, you need to catch the URL. I did this using intent-filter in AndroidManifest.xml

之后,您需要捕获URL。我是在AndroidManifest.xml中使用intent-filter完成的

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

It catch VIEW command and it only filter URL starting with id.web.freelancer.example.TCActivity://

它捕获VIEW命令,它只过滤以id.web.freelancer.example.TCActivity开头的URL://

Here's the package for you to try it out and here's the github repository. Hope this helped

这是你试用它的包,这里是github存储库。希望这有帮助

#2


34  

The following code worked for me on KitKat. I am yet to test on below versions of Android.

以下代码在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


10  

You may want only part of the text to be a clickable link, while the rest of the checkbox behaves as usual, i.e. you can click the other text to toggle the state.

您可能只希望文本的一部分是可单击的链接,而复选框的其余部分表现如常,即您可以单击其他文本以切换状态。

You can set up your checkbox like so:

您可以设置您的复选框,如下所示:

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


5  

I had the same problem and wanted to have more than one clickable links in the text of a checkbox without loosing the ability to click anywhere in the text (where there is no URL) to select/deselect the checkbox.

我遇到了同样的问题,希望在复选框的文本中有多个可点击的链接,而不会失去单击文本中任何位置(没有URL)的选项/取消选中复选框的功能。

The difference to the other answers to this question is that with this solution you can have multiple clickable links in the checkbox text and those links don't have to be at the end of the text.

与此问题的其他答案的不同之处在于,使用此解决方案,您可以在复选框文本中包含多个可单击链接,并且这些链接不必位于文本的末尾。

The layout looks similar to the one in ariefbayu's answer:

布局看起来类似于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 now set the text programmatically. The text I want to display is:

我现在以编程方式设置文本。我要显示的文字是:

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

As it contains HTML, I first convert it to a Spanned. To make the links clickable, I additionally set the movement method of the TextView to LinkMovementMethod:

由于它包含HTML,我首先将其转换为Spanned。为了使链接可单击,我还将TextView的移动方法设置为LinkMovementMethod:

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

And here comes the more tricky part. So far, the CheckBox does not get selected when pressing the TextView. To achive this, I added a touch handler to the TextView:

这里有更棘手的部分。到目前为止,按TabView时没有选中CheckBox。为了实现这一点,我在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;
    }
});

Finally, as you probably noticed, there is no method getOffsetForPosition(...) yet. If you're targeting API level 14+, you can simply use getOffsetForPosition(), as pointed out by Dheeraj V.S.. As I target API level 8+, I used an implementation that I found here: Determining which word is clicked in an android textview.

最后,正如您可能已经注意到的那样,还没有方法getOffsetForPosition(...)。如果你的目标是API级别14+,你可以简单地使用getIffsetForPosition(),正如我在Dheeraj VS中指出的那样。当我使用我在这里找到的API实现时,我使用了一个实现:确定在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


3  

Create a CheckBox with no text and add two TextViews next to it. The first is a non-clickable view with text like "I have read and agree to the ". The second is a clickable view with text like "TERMS AND CONDITIONS". Place the TextViews side by side without any margin. Notice the extra space in the end of the first view for natural text alignment. This way you could style both texts as you like.

创建一个没有文本的CheckBox,并在其旁边添加两个TextView。第一个是不可点击的视图,文字如“我已阅读并同意”。第二个是可点击的视图,其中包含“条款和条件”等文本。将TextViews并排放置,没有任何边距。注意第一个视图末尾的额外空格,以进行自然文本对齐。这样您就可以根据需要设置两种文本的样式。

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


Then add an onClick() handler in the code. Voilá.

然后在代码中添加一个onClick()处理程序。瞧。

public class SignUpActivity extends Activity {

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

#6


0  

If you look for a solution with the URL, i suggest you to use follow solution. With CheckBox and TextView.

如果您使用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);

where URL_TERMS_AND_CONDS = "yourUrl.com"; and R.string.terms_and_conds = id to the resource with the clickable string.

其中URL_TERMS_AND_CONDS =“yourUrl.com”;和R.string.terms_and_conds =具有可点击字符串的资源的id。

#7


0  

I didn't like the solution with the checkBox + textView as your custom view will extend a ViewGroup and not CheckBox thus forcing you to wrap CheckBox behavior.

我不喜欢使用checkBox + textView的解决方案,因为您的自定义视图将扩展ViewGroup而不是CheckBox,因此强制您包装CheckBox行为。

It was important to me that the custom CheckBox can be used in xml exactly like a regular one.

对我来说很重要的是,自定义CheckBox可以像xml一样在xml中使用。

The acceptable behavior for me was that this CheckBox will only be toggled when you press on it's box and not on it's text.

对我来说可接受的行为是,当你按下它的盒子而不是它的文本时,这个CheckBox才会被切换。

So I've extended CheckBox, and in order to achieve this behavior I've played with the whole touch mechanism, the full code is below, and an explanation right after it for anyone who like to know how it works.

所以我扩展了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();
}
}

it relays on the fact that performClick method is call internally by the TextView mechanism that CheckBox extends, the ClickableSpan is also called by the TextView Mechanism. so what happens is that when you touch your CheckBox's text it will call both.

它继承了这样一个事实:performClick方法是由CheckBox扩展的TextView机制内部调用的,ClickableSpan也是由TextView机制调用的。所以当你触摸CheckBox的文本时它会调用两者。

So What I've done is detect if the click was in the text area, if so we will disable the perfomClick thus disabling the toggle. but the clickable span will still be called.

所以我所做的是检测点击是否在文本区域,如果是,我们将禁用perfomClick,从而禁用切换。但仍会调用可点击的范围。

Usage:

You still need to add a clickable span and setMovementMethod as before, just like a regular TextView.

您仍然需要像以前一样添加可点击范围和setMovementMethod,就像常规TextView一样。

#1


24  

There actually is an elegant solution, using CheckBox and single TextView. Along with a combinations of TextView.setClickable(), Intent Filter, and TextView.setMovementMethod().

实际上有一个优雅的解决方案,使用CheckBox和单个TextView。与TextView.setClickable(),Intent Filter和TextView.setMovementMethod()的组合一起使用。

You have main view (here, I called it ClickableTextViewExample):

你有主视图(这里,我称之为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>

and the final piece of codes that glue it all, the AndroidManifest.xml:

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>

Here comes, the explanations:

来了,解释:

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 will allow you to click on textView. But not the HREF link. To do that, you will have to use setMovementMethod() and set it to LinkMovementMethod.

setClickable将允许您单击textView。但不是HREF链接。为此,您必须使用setMovementMethod()并将其设置为LinkMovementMethod。

After that, you need to catch the URL. I did this using intent-filter in AndroidManifest.xml

之后,您需要捕获URL。我是在AndroidManifest.xml中使用intent-filter完成的

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

It catch VIEW command and it only filter URL starting with id.web.freelancer.example.TCActivity://

它捕获VIEW命令,它只过滤以id.web.freelancer.example.TCActivity开头的URL://

Here's the package for you to try it out and here's the github repository. Hope this helped

这是你试用它的包,这里是github存储库。希望这有帮助

#2


34  

The following code worked for me on KitKat. I am yet to test on below versions of Android.

以下代码在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


10  

You may want only part of the text to be a clickable link, while the rest of the checkbox behaves as usual, i.e. you can click the other text to toggle the state.

您可能只希望文本的一部分是可单击的链接,而复选框的其余部分表现如常,即您可以单击其他文本以切换状态。

You can set up your checkbox like so:

您可以设置您的复选框,如下所示:

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


5  

I had the same problem and wanted to have more than one clickable links in the text of a checkbox without loosing the ability to click anywhere in the text (where there is no URL) to select/deselect the checkbox.

我遇到了同样的问题,希望在复选框的文本中有多个可点击的链接,而不会失去单击文本中任何位置(没有URL)的选项/取消选中复选框的功能。

The difference to the other answers to this question is that with this solution you can have multiple clickable links in the checkbox text and those links don't have to be at the end of the text.

与此问题的其他答案的不同之处在于,使用此解决方案,您可以在复选框文本中包含多个可单击链接,并且这些链接不必位于文本的末尾。

The layout looks similar to the one in ariefbayu's answer:

布局看起来类似于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 now set the text programmatically. The text I want to display is:

我现在以编程方式设置文本。我要显示的文字是:

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

As it contains HTML, I first convert it to a Spanned. To make the links clickable, I additionally set the movement method of the TextView to LinkMovementMethod:

由于它包含HTML,我首先将其转换为Spanned。为了使链接可单击,我还将TextView的移动方法设置为LinkMovementMethod:

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

And here comes the more tricky part. So far, the CheckBox does not get selected when pressing the TextView. To achive this, I added a touch handler to the TextView:

这里有更棘手的部分。到目前为止,按TabView时没有选中CheckBox。为了实现这一点,我在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;
    }
});

Finally, as you probably noticed, there is no method getOffsetForPosition(...) yet. If you're targeting API level 14+, you can simply use getOffsetForPosition(), as pointed out by Dheeraj V.S.. As I target API level 8+, I used an implementation that I found here: Determining which word is clicked in an android textview.

最后,正如您可能已经注意到的那样,还没有方法getOffsetForPosition(...)。如果你的目标是API级别14+,你可以简单地使用getIffsetForPosition(),正如我在Dheeraj VS中指出的那样。当我使用我在这里找到的API实现时,我使用了一个实现:确定在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


3  

Create a CheckBox with no text and add two TextViews next to it. The first is a non-clickable view with text like "I have read and agree to the ". The second is a clickable view with text like "TERMS AND CONDITIONS". Place the TextViews side by side without any margin. Notice the extra space in the end of the first view for natural text alignment. This way you could style both texts as you like.

创建一个没有文本的CheckBox,并在其旁边添加两个TextView。第一个是不可点击的视图,文字如“我已阅读并同意”。第二个是可点击的视图,其中包含“条款和条件”等文本。将TextViews并排放置,没有任何边距。注意第一个视图末尾的额外空格,以进行自然文本对齐。这样您就可以根据需要设置两种文本的样式。

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


Then add an onClick() handler in the code. Voilá.

然后在代码中添加一个onClick()处理程序。瞧。

public class SignUpActivity extends Activity {

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

#6


0  

If you look for a solution with the URL, i suggest you to use follow solution. With CheckBox and TextView.

如果您使用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);

where URL_TERMS_AND_CONDS = "yourUrl.com"; and R.string.terms_and_conds = id to the resource with the clickable string.

其中URL_TERMS_AND_CONDS =“yourUrl.com”;和R.string.terms_and_conds =具有可点击字符串的资源的id。

#7


0  

I didn't like the solution with the checkBox + textView as your custom view will extend a ViewGroup and not CheckBox thus forcing you to wrap CheckBox behavior.

我不喜欢使用checkBox + textView的解决方案,因为您的自定义视图将扩展ViewGroup而不是CheckBox,因此强制您包装CheckBox行为。

It was important to me that the custom CheckBox can be used in xml exactly like a regular one.

对我来说很重要的是,自定义CheckBox可以像xml一样在xml中使用。

The acceptable behavior for me was that this CheckBox will only be toggled when you press on it's box and not on it's text.

对我来说可接受的行为是,当你按下它的盒子而不是它的文本时,这个CheckBox才会被切换。

So I've extended CheckBox, and in order to achieve this behavior I've played with the whole touch mechanism, the full code is below, and an explanation right after it for anyone who like to know how it works.

所以我扩展了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();
}
}

it relays on the fact that performClick method is call internally by the TextView mechanism that CheckBox extends, the ClickableSpan is also called by the TextView Mechanism. so what happens is that when you touch your CheckBox's text it will call both.

它继承了这样一个事实:performClick方法是由CheckBox扩展的TextView机制内部调用的,ClickableSpan也是由TextView机制调用的。所以当你触摸CheckBox的文本时它会调用两者。

So What I've done is detect if the click was in the text area, if so we will disable the perfomClick thus disabling the toggle. but the clickable span will still be called.

所以我所做的是检测点击是否在文本区域,如果是,我们将禁用perfomClick,从而禁用切换。但仍会调用可点击的范围。

Usage:

You still need to add a clickable span and setMovementMethod as before, just like a regular TextView.

您仍然需要像以前一样添加可点击范围和setMovementMethod,就像常规TextView一样。