Android. How to get substring from Spannable which was clicked? - android

I have html string:
htmlString = "This is a link and another link link2"
I set this String to my TextView. Here is my code:
tvText.setText(Html.fromHtml(htmlString));
And also I set LinkMovementMethod, links to be clickable.
tvText.setMovementMethod(LinkMovementMethod.getInstance());
Everything is fine, but links open in the browser by default, and I need to open them inside the application in web view.
Can I somehow get the link from the clicked String ? So that I can load the link in web view.
Or do I need to manually search for all links in the String and put clicks on them (ClickableSpan)?
Please, help me.

Here is how you can do it:
Extend LinkMovementMethod to accept custom click listener
Copy this java class: InternalLinkMovementMethod to your project
Add set the link movement method of your TextView to this custom one, providing a click listener:
OnLinkClickedListener clickListener = new OnLinkClickedListener() {
#Override
public boolean onLinkClicked(String linkText) {
// here you can handle your click, eg show the dialog
// `linkText` is the text being clicked (the link)
// return true if handled, false otherwise
}
}
yourTextView.setMovementMethod(new InternalLinkMovementMethod(clickListener)
Base on: Intercept link LinkMovementMethod with a Yes/No dialog

Related

Intercept link LinkMovementMethod with a Yes/No dialog

I have a standard LinkMovementMethod established in my TextView to push a web Activity of some sort when the user touches a link. However, I want to establish a "do you want to see the link" dialog rather than taking the user straight to the webpage. I've tried overriding the touch methods but it all gets a little convoluted. A little help?
You can accomplish it in two ways:
Create custom Spans: more complicated, but you can accomplish more customised text consisting of clickable parts (or bold, differently coloured etc). To know more, check out ClickableSpan and SpannableStringBuilder
Extend LinkMovementMethod to accept custom click listener
In my opinion second solution is better in basic cases like yours. Here is how you can do it:
Copy this java class: InternalLinkMovementMethod to your project
Add set the link movement method of your TextView to this custom one, providing a click listener:
OnLinkClickedListener clickListener = new OnLinkClickedListener() {
#Override
public boolean onLinkClicked(String linkText) {
// here you can handle your click, eg show the dialog
// `linkText` is the text being clicked (the link)
// return true if handled, false otherwise
}
}
yourTextView.setMovementMethod(new InternalLinkMovementMethod(clickListener));

Android web link in textView inside ListView

I want to create a link in text view.
My link look like so:
The text to the link I get from array.xml
<item>Icons made by Freepik</item>
I already read set movement method
textView.setMovementMethod(LinkMovementMethod.getInstance());
This has no impact
and
android:autoLink="web"
This works if the text is http://www.freepik.com, but not if I want to have a custom text as link.
viewHolder.textView.setClickable(true);
viewHolder.textView.setText(text);
viewHolder.textView.setMovementMethod(LinkMovementMethod.getInstance());
This is a code which I am using to fill textView
I want in the end text looking like so:
Icons made by Freepik
I think you can't accomplish what you want in this way.
I think the simplest solution is to separate your links in differents list items. Keep in mind that you could use different TextView with different heights for example
Alternatively you could pass to a custom view approach. If you create a custom view (for example MultiLinkView), then you could add this view to the ListView.
I suggest this solution because this approach allow you to add a powerful logic to the view item.
I can't give you the complete code because it should be too long, but I can put you in the right way.
A custom view is a real Java class that extends some Android view class. So when you instantiate a CustomView you can pass to its constructor all the params you want (references, links, arrays and so on).
Start here
My idea is to find a way to pass all the parameters you need to your custom view and then find a way to represent your data, mapping them to your links.
I think you should abandon html solution in favor to ClickableSpan.
This is a piece of code that I used in a project to make clickable a single part of my string:
String text = "Hello <b>click me!</b> to go to internet!";
// create Spanned
Spanned spanned = Html.fromHtml(text);
// create SpannableString
SpannableString spanString = new SpannableString(spanned);
// set clickable part
ClickableSpan clickablePart = new ClickableSpan() {
#Override
public void onClick(View textView) {
if (connectionDetector.isConnectedToInternet()) {
// open browser or webview fragment
}
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
ds.setColor(Color.WHITE);
}
};
int startClickMe = spanString.toString().indexOf(text);
spanString.setSpan(clickablePart, startClickMe, text.length() + startClickMe, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Obviously in the onClick you should find a way to get the right link, but, as I said before, in a custom view you can put as many variables as you want. I'm sure that you can find a solution.
Let me know if it helps

Android - In-line autocomplete with EditText

I want to get an in-line autocomplete with an EditText, not a result list but the best suggestion directly in EditText.
Something like this : In-line auto-complete (near the bottom of the page).
Is it possible in Android ?
Thank you.
I have no eclipse now so I will try to give you some hints.
To create a custom autocomplete I would do something like this.
First
In the view layout add the EditText and an OutputText (this with visibility=hidden)
Second
In the activity create a TextWatcher and implement the method afterTextChanged.
Inside this method call a service with the input text and then update the content of the outputText.
Something like:
afterTextChanged(Editable s){
// you know your input is an EditText
final EditText input= (EditText) s;
// TODO make this call async
String suggestedText= someService.getSuggestion(input.getString());
outputText.setText(suggestedText);
outputText.setVisibility(View.VISIBLE);
// to avoid infinite loops
if(suggestedText!=null && !"".equals(suggestedText) && !suggestedText.equals(input.getString())
{
// add a onclick control to update the input
outputText.setOnClickListener(new View.OnClickListener(){
editText.setText(suggestedText);
});
}
}
Third
Implement the suggestion service.
Android has an AutoCompleteTextView which should do the job you want.
According to the official Android docs
"AutoCompleteTextView is an editable text view that shows completion suggestions automatically while the user is typing. The list of suggestions is displayed in a drop down menu from which the user can choose an item to replace the content of the edit box with.
The drop down can be dismissed at any time by pressing the back key or, if no item is selected in the drop down, by pressing the enter/dpad center key.
The list of suggestions is obtained from a data adapter and appears only after a given number of characters defined by the threshold."
For an example code snippet refer to AutoCompleteTextView
For autocomplete you must another type of EditText called AutocompleteTextView or MultiAutocompleteTextView. Here you can find simple example for that option.
P.S. if you want to create your own type of List Filtration, your Adapter class must implement Filterable interface

How to make a TextView clickable but not to launch with the phone's browser

I am creating an Android Browser and within my browser i am making a Favorites page.
In my favorite page, i have an EditText, where i insert the adress of the website i want to add, a remove button which removes all favorites and a TextView where the added websites are displayed.
My question is ...how can i make the adresses displayed in the TextView to be links, not only strings, BUT to be opened inside my browser?
All my tries so far ended up opening it with the phone's browser. My browser is structured like this: A menu, which is an OnListItemClick, where i can select HomePage, which has the main thing where you can browse the internet, with back and forward, refresh buttons.
In the menu, after the HomePage, i have Favorites, History and Settings. I need it to start the HomePage and to acces the site when i click the link from the favorites TextView. Can anyone give me an idea how to do it? I am sure i need to make a huge method for that, but I don't know how to start.
Know this is pretty late. Just think others might also find this useful.
You can implement your own ClickableSpan to achieve that. You can create a Spannable from scratch and assign to TextView like:
Spannable text = Spannable.newSpannable("Source text with link");
ClickableSpan link = new ClickableSpan {
public abstract void onClick (View widget) {
// Implement your own link behaviour
}
}
text.setSpan(clickable, startPos, endPos, flags);
textView.setText(text);
Or, if your source is html, you can use Html.fromHtml("Source text with <a href='whatever'>link</a>") which parses the HTML and converts links into URLSpan for you. You then need to replace all URLSpan with your own ClickableSpan like above. (see Spanned#getSpans and Spannable)
This can be tedious. Thus I created a library Textoo to simplify the matter. With Textoo you can achieve the same like:
Spanned linksLoggingText = Textoo
.config("Links: <a href='http://www.google.com'>Google</a>")
.parseHtml()
.addLinksHandler(new LinksHandler() {
#Override
public boolean onClick(View view, String url) {
Log.i("MyActivity", "Linking to google...");
return false; // event not handled. Continue default processing i.e. link to google
}
})
.apply();

Passing data on button press

I have sort of a file manager. It displays files in a ListView. Each of those ListViews has a custom footer - a button, which is defined in a xml file. Pressing a button allows user to chose a file from the "downloads" directory and copy it to the folder where the button was pressed. This is implemented through the AlertDialog. So by clicking the option from the dialog I get a path of a file that should be copied.
Now, how do I get the location from which my button was pressed? Can I somehow pack some sort of data in my button on its creation so that later when it is pressed I could identify its initial location?
there are many ways to achieve that. you can create a separate OnClickListener for each button as JaLoveAst1k proposes. you could also add some information to the buttons's tag (setTag()) and get it back in the onClick() function. Yet another way would be to have a Hashtable<Button, String> where you store your string informaton relative to the Button.
Yes, like this:
protected class CustomListener implements View.OnClickListener {
private String text;
public CustomListener(String text) {
this.text = text;
}
...
}
And set this listener to button, in constructor give data.

Categories

Resources