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.
Related
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'm trying to make an array of strings individually clickable within a text view that is within a RecyclerView (each tag would pass different data, which is fetched from the api on load). I've created the string using SpannableStringBuilder as below within the bindView method.
fun bindView(link: PostsModel)
val tags = link.topics
var spans = SpannableStringBuilder()
for (tag in tags) {
val string = SpannableString(tag.name)
string.setSpan(ClickableTags(tag.name), 0, tag.name.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
spans.append(string)
}
}
Then I set it to the text view.
view.headerTags.setText(spans, TextView.BufferType.SPANNABLE)
If I println() the contents of spans and view.headerTags.text, I can see it contains a string of tags, so it seems to be working. However, when testing in the app, it's not appearing in the text view.
If I set view.headerTags.text = "Tags should appear here", it works, so I'm not sure there's a problem with the text view.
Can't see to work out why it wouldn't appear, especially if the console is printing out the contents of text view? Can anyone let me know what I might be missing here?
Please use
Spannable word2 = new SpannableString("By signing in, I agree to The xxxxx\nxxxxxxx Terms of Service and Privacy Policy.");
word2.setSpan(clickableSpan, 44, 60, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
word2.setSpan(clickableSpan1, 65, 80, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(word2);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
Intent intent = new Intent(SignInActivity.this, ReadTermsOfServiceActivity.class);
intent.putExtra("FROM", "termsservices");
startActivity(intent);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
I'm integrating Firebase to support Deeplink feature in app. I have seen in one of screen-example suggested(PFA) here that we can add our own custom text instead of display Deep link URL.
I have tried to update but that did not help. How to do that, Any suggestion?
My guess is that you are using a UITextView for when the user enters text (in iOS). Here is how to accomplish that in Swift:
class ViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonPress(_ sender: Any) {
let range = textView.selectedRange
let linkString = NSMutableAttributedString(string: textView.text)
linkString.addAttribute(NSLinkAttributeName, value: textField.text ?? "", range: range)
textView.attributedText = linkString
}
}
extension ViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
UIApplication.shared.open(URL, options: [:], completionHandler: nil)
return false
}
}
In Android, I found a couple of SO answers that seem to handle the topic well:
Make a hyperlink textview in android
From user370305:
Try this, and let me know what happen..
TextView textView =(TextView)findViewById(R.id.textView);
textView.setClickable(true);
textView.setMovementMethod(LinkMovementMethod.getInstance());
String text = "<a href='http://www.google.com'> Google </a>";
textView.setText(Html.fromHtml(text));
Put html link in edittext android
From RobinHood:
Put your html in a string#
<string url="link"><a href="http://www.google.com">Google</a></string>
set String to editText#
youredittext.setText(Html.fromHtml(getResources().getString(R.string.url)));
For click, set LinkMovementMethod with necessary action#
youredittext.setMovementMethod(LinkMovementMethod.getInstance());
If you are trying to accomplish this in HTML, then use an anchor (a) tag:
<p>Click on this Link</p>
I have done the same thing in one of my apps. Please follow below code.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="#dimen/margin"
tools:context="tdsolutions.com.clickabletext.MainActivity">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World this text" />
</LinearLayout>
Pass your Textview to below method(setClickableText):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text = (TextView) findViewById(R.id.text);
setClickableText(text);
}
private void setClickableText(TextView textView) {
String text = "this"; // the text you want to mark as a link
SpannableString ss = new SpannableString(textView.getText());// full text
final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.parseColor("#91ca46"));//link text color
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
//What ever the code you want when click on text goes here
Toast.makeText(MainActivity.this,"you clicked",Toast.LENGTH_LONG).show();
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
int start = textView.getText().toString().indexOf(text);
int length = start + text.length();
ss.setSpan(clickableSpan, start, length, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ss.setSpan(fcs, start, length, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);
}
Or you can use below code:
Add the text view as below, change whatever the attributes as you wish.
<TextView
android:id="#+id/textView"
android:layout_centerInParent="true"
android:linksClickable="true"
android:textColorLink="#00f"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
then add below code:
TextView textView = (TextView) findViewById(R.id.textView);
Spanned result;
String html = "Hi sweetheart go to this link";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
result = Html.fromHtml(html ,Html.FROM_HTML_MODE_LEGACY);
} else {
result = Html.fromHtml(html);
}
textView.setText(result);
textView. setMovementMethod(LinkMovementMethod.getInstance());
please make sure when you add links replace them with html tags as I did in the example String html = "Hi sweetheart go to this link";
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 have a TextView that displays some HTML code (images included, ImageGetter).
The html is not mine, but I can ask them to include custom scheme links, maybe even tags.
Purpose: to display some dynamically generated content without the need to play with nested Android layouts.
Problem: some links must be handled in the application (new Fragment loaded).
Can't use a receiver for action.VIEW, since it's an Activity Intent, not a broadcast, and its use will be very contextual, so only a programmatically registered receiver would do.
I'm usingtextView.setText(Html.fromHtml(content.content, imageGetter, null). need everything to remain the same, except some spans should have my own onClick on it. I'm not very familiar with Spanned, so I see these options:
Edit the SpannableStringBuilder returned from Html.fromHtml, and replace the URLSpans I want with a custom ClickableSpan (how?)
As above, but copy everything to a new builder, exchanging the URLSpans for my own (how? append takes a CharSequence only, and I get RelativeSizeSpan, StyleSpan, ImageSpan, URLSpan...)
Create a Spanned manually. I can do it for the custom scheme, but how to duplicate the effect of Html.fromHtml (or close enough) for all else?
[edit]
Thanks to MH. for the info. I had tried that before, but failed. Now that i returned to it, I found i had made an error, passing the wrong item to the 1st argument of setSpan.
If anyone's interested, i now use this:
public static interface OnSpanClickListener {
void onClick(String url);
}
public static SpannableStringBuilder getSpannable(String source, ImageGetter imageGetter, String scheme, final OnSpanClickListener clickHandler){
SpannableStringBuilder b = (SpannableStringBuilder) Html.fromHtml(source, imageGetter, null);
for(URLSpan s : b.getSpans(0, b.length(), URLSpan.class)){
String s_url = s.getURL();
if(s_url.startsWith(scheme+"://")){
URLSpan newSpan = new URLSpan(s_url.substring(scheme.length()+3)){
public void onClick(View view) {
clickHandler.onClick(getURL());
}
};
b.setSpan(newSpan, b.getSpanStart(s), b.getSpanEnd(s), b.getSpanFlags(s));
b.removeSpan(s);
}
}
return b;
}
(...)
body.setText(getSpannable(content.content, imageGetter, getResources().getString(R.string.poster_scheme), new OnSpanClickListener(){
public void onClick(String url) {
// do whatever
}
}));
Option 1 is probably most straightforward and most of the hard work for it has already been done before. You've got the general idea correct: after the HTML has been processed, you can request all the generated URLSpan instances and loop through them. You can then replace it with a customized clickable span to get full controls over any of the span clicks.
In the example below, I'm just replacing every URLSpan with a simple extension of that class that takes the original url (actually, I should probably say 'uri') and replace its scheme part. I've left the actual onClick() logic unimplemented, but I'll leave that up to your imagination.
SpannableStringBuilder builder = ...
URLSpan[] spans = builder .getSpans(0, builder .length(), URLSpan.class);
for (URLSpan span : spans) {
int start = builder .getSpanStart(span);
int end = builder .getSpanEnd(span);
s.removeSpan(span);
span = new CustomURLSpan(span.getURL().replace("http://", "scheme://"));
s.setSpan(span, start, end, 0);
}
textView.setText(builder);
As mentioned earlier, here the CustomURLSpan class is a simple extension of URLSpan that takes a url and overrides the onClick() method so our own logic can be executed there.
public class CustomURLSpan extends URLSpan {
public CustomURLSpan(String url) {
super(url);
}
#Override public void onClick(View widget) {
// custom on click behaviour here
}
}
Some related Q&A's that basically do a similar thing (might be helpful for some more inspiration):
Can I change TextView link text after using Linkify?
Remove underline from links in TextView - Android
As you will use TextView.setMovementMethod(LinkMovementMethod.getInstance()) to make it respond for the partly click, you can implement a customized LinkMovementMethod to intercept the click event and process your own logic.
public class CustomLinkMovementMethod extends LinkMovementMethod {
private HashMap<Class, SpanProxy> spansProxy = new HashMap<>();
public CustomLinkMovementMethod setSpanProxy(Class spanClazz, SpanProxy proxy) {
spansProxy.put(spanClazz, proxy);
return this;
}
public CustomLinkMovementMethod removeSpanProxy(Class spanClazz) {
spansProxy.remove(spanClazz);
return this;
}
#Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
SpanProxy spanProxy = spansProxy.get(ClickableSpan.class);
if(spanProxy != null) {
spanProxy.proxySpan(link[0], widget);
} else {
link[0].onClick(widget);
}
return true;
}
}
}
return super.onTouchEvent(widget, buffer, event);
}
public interface SpanProxy {
void proxySpan(Object span, View widget);
}
}
And used like this:
textView.setMovementMethod(new CustomLinkMovementMethod().setSpanProxy(ClickableSpan.class,
new CustomLinkMovementMethod.SpanProxy() {
#Override
public void proxySpan(Object span, View widget) {
if (span instanceof URLSpan) {
URLSpan urlSpan = (URLSpan) span;
String url = urlSpan.getURL();
// do what you want with the link
// tbd
return;
}
if (span instanceof ClickableSpan) {
((ClickableSpan) span).onClick(widget);
}
}
}));