I am working on chat project. For showing chat messages I am using the following layout
<TextView
android:id="#+id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="web"
android:longClickable="true"
android:textColor="#000000"
tools:text="hello hello hello hello" />
And on java side, I am simply formatted the message text and then set it to the TextView.
I am facing 2 main issues:
When I click on weblink in the message, screen scrolls either top or bottom. This does not happen when I click the non-weblink portion of the message.
Click doesn't navigate to the corresponding webpage. With too much difficulty, sometimes it happens that I am able to navigate to the webpage.
Things I have tried:
I tried using the setMovementMethod(context) method after setting the text but didn't work.
I also tried things like removing the autoLink="web" from layout as suggested by some.
I also tried setLinksClickable(true) and setAutoMask(0) but nothing is working.
I have spent quite some time on it now. Can someone help me here.
Thanks in advance.
you must use an inherited class from ClickableSpan, as such setLinksClickable TextView's method is not enough, each link in the text assigned to TextView must have the click event.
The solution is coded in Xamarin, but i thinks is easily translatable to Java.
With this function, we check de html string text, and we get the links and make each of them clickable with MakeLinkClickable function.
public static void SetTextAsHtmlWithOverrideLinks(Android.Widget.TextView textview, string text)
{
var sequence = text.GetTextAsHtml();
var strBuilder = new Android.Text.SpannableStringBuilder(sequence);
var urls = strBuilder.GetSpans(0, sequence.Length(), Java.Lang.Class.FromType(typeof(Android.Text.Style.URLSpan)));
foreach (Android.Text.Style.URLSpan span in urls) {
MakeLinkClickable(strBuilder, span);
}
textview.MovementMethod = Android.Text.Method.LinkMovementMethod.Instance;
textview.TextFormatted = strBuilder;
}
This function makes each link clickable with LinkSpan class, which has our action on link click
public static void MakeLinkClickable(Android.Text.SpannableStringBuilder strBuilder, Android.Text.Style.URLSpan span)
{
strBuilder.SetSpan(new LinkSpan(span), strBuilder.GetSpanStart(span), strBuilder.GetSpanEnd(span),strBuilder.GetSpanFlags(span));
strBuilder.RemoveSpan(span);
}
public class LinkSpan : Android.Text.Style.ClickableSpan
{
public Android.Text.Style.URLSpan Link { get; }
public LinkSpan(Android.Text.Style.URLSpan span) {
Link = span;
}
public override void OnClick(Android.Views.View widget)
{
if (widget is Android.Widget.TextView textView)
// Here open url or another action with your own method;
widget.Invalidate();
}
}
This function converts our html text to a spannable text to handle it.
public static Android.Text.ISpanned GetTextAsHtml(this string input)
{
if (input == null)
input = string.Empty;
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
return Android.Text.Html.FromHtml(input,Android.Text.FromHtmlOptions.ModeLegacy);
else
return Android.Text.Html.FromHtml(input);
}
Use:
SetTextAsHtmlWithOverrideLinks(yourtextView, theHTMLTextString);
I am having a edit text which is behaving like feeds in face book. So whenever i post something like "www.google.com" it is showing as hyperlink, But at the same time whenever i post something like "abcd.abcd" , it is also showing me as a hyper link. I want to show my post as link only when i add "http" or "www" , How to achieve this. Thanks in advance
<EditText
android:id="#+id/etFeedsText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="50dp"
android:maxLength="2000"
android:layout_marginBottom="25.8dp"
android:layout_marginLeft="14dp"
android:layout_marginTop="8.3dp"
android:hint="#string/enter_your_post"
android:background="#color/white"
android:inputType="textMultiLine|textNoSuggestions"
android:textColor="#color/feeds_text"
android:textSize="13.3sp" />
You can compare your text & can find out if its a valid URL or not by this method,
/**
* This is used to check the given URL is valid or not.
* #param url
* #return true if url is valid, false otherwise.
*/
private boolean isValidUrl(String url) {
Pattern p = Patterns.WEB_URL;
Matcher m = p.matcher(url.toLowerCase());
return m.matches();
}
If the text is not an URL then remove the underline from bottom like,
if(!isValidUrl(yourUrl)){
stripUnderlines(TextView textView)
}
private void stripUnderlines(TextView textView) {
Spannable s = new SpannableString(textView.getText());
URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
for (URLSpan span: spans) {
int start = s.getSpanStart(span);
int end = s.getSpanEnd(span);
s.removeSpan(span);
span = new URLSpanNoUnderline(span.getURL());
s.setSpan(span, start, end, 0);
}
textView.setText(s);
}
It requires a customized version of URLSpan which doesn't enable the TextPaint's "underline" property:
private class URLSpanNoUnderline extends URLSpan {
public URLSpanNoUnderline(String url) {
super(url);
}
#Override public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
}
Hope this help!
Just add this to your Edittext
Linkify.addLinks(etFeedsText, Linkify.WEB_URLS);
This will consider only valid URLs.
Also you can use a textview, if you are just displaying the data. Edittext is not necessary.
I have a TextView in listview which can have 2+ links. I had gone through to this SO link to capture the event of a TextView but this is not working for a list view.
Here is my code:
getView method
if(ann.message.contains("<a href=")){
setTextViewHTML(holder.announcement, ann.message);
}
methods to make text clickable
protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
// Do something with span.getURL() to handle the link click...
Log.i("YES-5.0", span.getURL());
}
};
strBuilder.setSpan(clickable, start, end, flags);
strBuilder.removeSpan(span);
}
protected void setTextViewHTML(TextView text, String html)
{
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) {
makeLinkClickable(strBuilder, span);
}
text.setText(strBuilder);
}
This is my TextView:
<TextView
android:id="#+id/textViewAnnouncementMessage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="4dp"
android:focusable="false"
android:textColor="#android:color/black"
android:maxLines="5"
android:text="#string/message"
android:textSize="16sp"/>
I have tried with all the combinations of following attributes of `TextView' but still no success:
android:autoLink="all"
android:clickable="true"
android:linksClickable="true"
Have you set your movement method on your TextView? Also, if your link comes as an a href tag, you can just use Html.fromHtml to build your Spannable for you. For example:
TextView mView = (TextView) findViewById(R.id.text1);
mView.setMovementMethod(LinkMovementMethod.getInstance());
mView.setText(Html.fromHtml(YOUR_LINK_STRING));
if you use a XML Layout for your textview and that your clickable links all start with http:// il devrait etre suffisant d'utiliser les attributs suivants:
<TextView
...
android:autoLink="all"
android:linksClickable="true"
android:textColorLink="#color/colorAccent" />
autoLink all means that all mailAdress, http link and phone numbers will be clickable. Just give a look at official documentation for further details: http://developer.android.com/reference/android/text/util/Linkify.html#ALL
I solved my problem by adding following line before calling setTextViewHTML():
holder.announcement.setMovementMethod(LinkMovementMethod.getInstance());
So now my getView() method looks like:
if(ann.message.contains("<a href=")){
holder.announcement.setMovementMethod(LinkMovementMethod.getInstance());
setTextViewHTML(holder.announcement, ann.message);
}
I am using a text view in my aap, which is having plane text as well as a hyperlink. Now when I click on hyperlink then link open with default browser. But in actual I dont want to open default browser. Actually I want to register OnClickListener on hyperlink and want to perform other.
I searched on internet and I got this solution...
Control onclicklistener in autolink enabled textview
But this is not helpful for me.
Anyone can tell me that how I can perform this.
Thanks in advance
you can use a Spannable object
final Spannable span = new SpannableString(text);
span.setSpan(new ClickableSpan() {
#Override
public void onClick(View v) {
}
}, 0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
where text is your hyperlink
Remove android:autoLink="web" if this property setted into XML.
TextView textView =(TextView)findViewById(R.id.textView);
textView.setClickable(true);
when you want to open in browser use this code
textView.setMovementMethod(LinkMovementMethod.getInstance());
String text = "<a href='http://www.google.com'> Google </a>";
textView.setText(Html.fromHtml(text));
if you want to perform some operation register onclick listener for textview and perform.
textView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
Try doing this add
in your
main.xml
<TextView
android:id="#+id/yourTVID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="performSomeAction" />
in your SomeActivity.java
public void performSomeAction( View v){
//Perform your action
}
Try this, it should solve your problem. This method will return a Spannable String which have part of it clickable.
Before calling the below method you should Create CharSequence from the String then convert it to Spannable
CharSequence charSequencce = testView.getText();
Spannable spannable = (Spannable) charSequencce;
public SpannableStringBuilder addClickToPartsOfString(Spannable charSequence, String[] stringsToAddClick, final OnHyperLinkClickListener onClickListener) {
SpannableStringBuilder ssb = new SpannableStringBuilder(charSequence);
for(final String s : stringsToAddClick) {
int index1 = charSequence.toString().indexOf(s);
int index2 = (s.length() + index1);
ssb.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
onClickListener.onClick(s);
}
}, index1, index2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return ssb;
}
I've just made a library aiming to simplify this. See Textoo. You can achieve the same with code like:
TextView locNotFound = Textoo
.config((TextView) findViewById(R.id.view_location_disabled))
.addLinksHandler(new LinksHandler() {
#Override
public boolean onClick(View view, String url) {
if ("internal://settings/location".equals(url)) {
Intent locSettings = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(locSettings);
return true;
} else {
return false;
}
}
})
.apply();
Internally the library converts existing links in your textview / string resources (android system parse html links in string resources into Span for you already) into custom ClickableSpan and capture clicks into calls to your handlers.
This relieve you from having to calculate and hard coding the position of clickable spans to add. Thus make it easier to externalize your text into string resources and better for localization.
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).
How can I accomplish this?
Thanks in advance.
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());
The following code worked for me on KitKat. I am yet to test on below versions of 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());
There actually is an elegant solution, using CheckBox and single TextView. Along with a combinations of TextView.setClickable(), Intent Filter, and TextView.setMovementMethod().
You have main view (here, I called it 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:
<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.
After that, you need to catch the URL. I did this using intent-filter in AndroidManifest.xml
<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://
Here's the package for you to try it out and here's the github repository. Hope this helped
Kotlin version (through an extension) of Daniel Schuler's answer :
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
}
Usage :
yourCheckBox.addClickableLink(
fullText = "This link must be clickable",
linkText = SpannableString("This link")
) {
// Do whatever you want when onClick()
}
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.
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:
<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:
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:
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.
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);
}
Requirements:
only part of the text to be a clickable link, while the rest of the Checkbox behaves as usual:
Prevent CheckBox state from being toggled when link is clicked
Remove ripple effect from CheckBox
Here is the Kotlin version:
interface HtmlAnchorClickListener {
fun onHyperLinkClicked(name: String)
}
fun addClickableSpan(linkableTextView: TextView?, htmlString: String, listener: HtmlAnchorClickListener) {
linkableTextView?.let {
val sequence = HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_LEGACY)
Log.d("addClickableSpan", "sequence = $sequence")
val spannableString = SpannableStringBuilder(sequence)
val urls = spannableString.getSpans(0, sequence.length, URLSpan::class.java)
urls.forEach { span ->
with(spannableString) {
val start = getSpanStart(span)
val end = getSpanEnd(span)
val flags = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
val linkColor = linkableTextView.context.getColor(R.color.light_blue)
val clickable = object : ClickableSpan() {
override fun onClick(view: View) {
// Prevent CheckBox state from being toggled when link is clicked
linkableTextView.cancelPendingInputEvents()
removeRippleEffectFromCheckBox(linkableTextView)
listener.onHyperLinkClicked(span.url)
}
override fun updateDrawState(textPaint: TextPaint) {
textPaint.color = linkColor
textPaint.isUnderlineText = true
}
}
setSpan(clickable, start, end, flags)
setSpan(ForegroundColorSpan(linkColor), start, end, flags)
removeSpan(span)
}
with(it) {
text = spannableString
linksClickable = true
movementMethod = LinkMovementMethod.getInstance()
}
}
}
}
fun removeRippleEffectFromCheckBox(textView: TextView) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
var drawable = textView.background
if (drawable is RippleDrawable) {
drawable = drawable.findDrawableByLayerId(0)
textView.background = drawable
}
}
}
Usage:
private fun setUpTermsOfUseHyperLink() {
val checkBoxText =
"I agree to all the <a href='http://www.redbus.in/mob/mTerms.aspx' > Terms and Conditions</a>"
addClickableSpan(cbAccept, checkBoxText, object : HtmlAnchorClickListener {
override fun onHyperLinkClicked(name: String) {
Toast.makeText(context!!, name, Toast.LENGTH_LONG).show()
}
})
}
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.
Sample xml code:
<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á.
public class SignUpActivity extends Activity {
public void onClick(View v) {
...
}
}
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.
It was important to me that the custom CheckBox can be used in xml exactly like a regular one.
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.
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.
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.
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.
Usage:
You still need to add a clickable span and setMovementMethod as before, just like a regular TextView.
If you look for a solution with the URL, i suggest you to use follow solution. With CheckBox and 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.
Here is a simple code snippet to make checkbox spannable string clickable in kotlin:
val myText = ... // your string.
val spannableStr = SpannableString(myText)
val clickableText1 = object : ClickableSpan() {
override fun onClick(widget: View) {
widget.cancelPendingInputEvents()
doMyWorkHere()
}
override fun updateDrawState(text: TextPaint) {
super.updateDrawState(text)
text.color = Color.RED
text.isUnderlineText = true
}
}
val clickableText2 = object : ClickableSpan() {
override fun onClick(widget: View) {
widget.cancelPendingInputEvents()
doMySecondWork()
}
override fun updateDrawState(textPaint: TextPaint) {
super.updateDrawState(textPaint)
textPaint.color = COLOR.BLUE
textPaint.isUnderlineText = false
}
}
spannableStr1.setSpan(clickableText1, 10, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
spannableStr2.setSpan(clickableText2, 30, 40, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
myCheckBox.text = spannableStr
myCheckBox.movementMethod = LinkMovementMethod.getInstance()
Happy Coding :)
Please try this one
String checkBoxText = "I agree to the Yunolearning <a href='https://blog.google/intl/en-in/' > Blogs</a> and <a href='https://about.google/stories/' > Stories</a>";
MaterialCheckBox singleCheckbox = new MaterialCheckBox(this);
singleCheckbox.setTag(formField.getName());
singleCheckbox.setText(Html.fromHtml(checkBoxText));
singleCheckbox.setMovementMethod(LinkMovementMethod.getInstance());