Sunday, October 20, 2013

Open URL, Linkify text and Spannable string in Android

In this post I will be going to describe how to open URL in Android and how to link text in different ways using default methods and spannable string.
Below are the different methods to linking text with URL:

1.Android's default method to link text with URL:
Here I added one text box :
<TextView android:id="@+id/text1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/link"/>

For this I am using below string :
 <string name="link"><a href="http://android2011dev.blogspot.com">Go to Android-Dev blog page.</a> </string>

and now will call this string on click of text view:
private void linkWithWeb()
{
TextView text1 = (TextView)findViewById(R.id.text1);
text1.setMovementMethod(LinkMovementMethod.getInstance());
}

It will look like this on device :


Here complete text is linked with URL.

2.In this second option I will link some part of string with URL and make the link text bold.
Add the text box:
<TextView android:id="@+id/text2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/bold_link"/>

Here is the bold_link string :
    <string name="bold_link">
Go to
<a STYLE="text-decoration:none" href="http://android2011dev.blogspot.com">
<b>Android Dev Blog</b>
</a> page.
</string>

Here we will be going to initialize text box and on click of text box app will launch above URL in web browser. Call below method on click of text box.

private void linkWithBoldWeb() {
TextView text2 = (TextView)findViewById(R.id.text2);
text2.setMovementMethod(LinkMovementMethod.getInstance());
}

It will look like this on device :



3. Change the text font and color of linking text
Text box:
<TextView android:id="@+id/text3" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/link"/>  
Here is the string:
<string name="custom_link_pre">Go to </string>
<string name="custom_link_end">Android Dev Blog </string>
<string name="custom_link_end_text">page.</string>
Here I used three strings, text before link text, link text and finally text after link.

Here is the method to build third text box:

String linkBlog = "http://android2011dev.blogspot.com";
private void cutomizeLink(){
TextView text3 = (TextView)findViewById(R.id.text3);
text3.setMovementMethod(LinkMovementMethod.getInstance());
String strLeading = getXMLString(this, R.string.custom_link_pre);
String strTrailing = getXMLString(this, R.string.custom_link_end);
String strTrailingEnd = getXMLString(this, R.string.custom_link_end_text);

SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(strLeading);
stringBuilder.append(" " + strTrailing);
stringBuilder.append(" " + strTrailingEnd);

stringBuilder.setSpan(new NonUnderlinedClickableSpan() {

@Override
public void onClick(View widget) {

Intent browse = new Intent(Intent.ACTION_VIEW, Uri.parse(linkBlog));
startActivity(browse);
}
}, strLeading.length(), strLeading.length() + strTrailing.length()+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

text3.setText(stringBuilder);
text3.setMovementMethod(LinkMovementMethod.getInstance());

}

getXMLString method is used for int to string conversion.
public static String getXMLString(Context context, int stringID) {

Resources res = context.getResources();
return res.getString(stringID);

}

NonUnderlinedClickableSpan class will be used to change the text color from default blue to megenta and removed underline from lined text.
public class NonUnderlinedClickableSpan extends ClickableSpan {
@Override
public void updateDrawState(TextPaint ds) {

ds.setColor(Color.MAGENTA);
ds.setUnderlineText(false);
ds.setTypeface(Typeface.DEFAULT_BOLD);

}

@Override
public void onClick(View v) {

}
}

It will look like this on device :


4. Here we will see how to multiple links in same string along with I will change the text font and color of linking text same as third option.
Add text box:
<TextView android:id="@+id/text4" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textSize="20sp"
    android:text="@string/custom_link_text"
    android:padding="15dip"/>

Then add string:
<string name="custom_link_text">Go to Google search page and Blog page.</string>

And now initialize and build the text box as per requirement:

String link = "http://www.google.com";
String linkBlog = "http://android2011dev.blogspot.com";

private void customLink(){
TextView text4 = (TextView)findViewById(R.id.text4);
text4.setMovementMethod(LinkMovementMethod.getInstance());
String customStr = getXMLString(this, R.string.custom_link_text);
String strLeading = customStr.substring(0, customStr.indexOf("Google"));
String strTrailing = customStr.substring(customStr.indexOf("Google"), (customStr.indexOf("search") - 1));
String strTrailingEnd = customStr.substring(0, (customStr.indexOf("Blog")));
String strTrailingEnd1 = customStr.substring((customStr.lastIndexOf("page")));
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(customStr);

stringBuilder.setSpan(new NonUnderlinedClickableSpan() {

@Override
public void onClick(View widget) {

Intent browse = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
startActivity(browse);
}
},strLeading.length(), 
strLeading.length() + strTrailing.length()+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

stringBuilder.setSpan(new NonUnderlinedClickableSpan() {

@Override
public void onClick(View widget) {

Intent browse = new Intent(Intent.ACTION_VIEW, Uri.parse(linkBlog));
startActivity(browse);
}
},strTrailingEnd.length(), 
strTrailingEnd.length() + strTrailingEnd1.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

text4.setText(stringBuilder);
text4.setMovementMethod(LinkMovementMethod.getInstance());

}
Here is the result :

On click of  'Google' app will navigate to "http://www.google.com" page and on click 'Blog' navigate to "http://android2011dev.blogspot.com" page.

That's it
Here is the complete source code :
Activity file:
public class SpannableStringActivity extends Activity {

String link = "http://www.google.com";
String linkBlog = "http://android2011dev.blogspot.com";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
linkWithWeb();
linkWithBoldWeb();
cutomizeLink();
customLink();
}
/*
* Used to linking with web
*/
private void linkWithWeb() {
TextView text1 = (TextView)findViewById(R.id.text1);
text1.setMovementMethod(LinkMovementMethod.getInstance());
}

/*
* Link with bold font
*/
private void linkWithBoldWeb() {
TextView text2 = (TextView)findViewById(R.id.text2);
text2.setMovementMethod(LinkMovementMethod.getInstance());
}

/*
* Change the text font and color of linking text
*/
private void cutomizeLink(){
TextView text3 = (TextView)findViewById(R.id.text3);
text3.setMovementMethod(LinkMovementMethod.getInstance());
String strLeading = getXMLString(this, R.string.custom_link_pre);
String strTrailing = getXMLString(this, R.string.custom_link_end);
String strTrailingEnd = getXMLString(this, R.string.custom_link_end_text);

SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(strLeading);
stringBuilder.append(" " + strTrailing);
stringBuilder.append(" " + strTrailingEnd);

stringBuilder.setSpan(new NonUnderlinedClickableSpan() {

@Override
public void onClick(View widget) {

Intent browse = new Intent(Intent.ACTION_VIEW, Uri.parse(linkBlog));
startActivity(browse);
}
}, strLeading.length(), strLeading.length() + strTrailing.length()+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

text3.setText(stringBuilder);
text3.setMovementMethod(LinkMovementMethod.getInstance());
}
/*
*  Change the text font and color of linking text. Add multiple links in to the single sentence.
*/
private void customLink(){
TextView text4 = (TextView)findViewById(R.id.text4);
text4.setMovementMethod(LinkMovementMethod.getInstance());
String customStr = getXMLString(this, R.string.custom_link_text);
String strLeading = customStr.substring(0, customStr.indexOf("Google"));
String strTrailing = customStr.substring(customStr.indexOf("Google"), (customStr.indexOf("search") - 1));
String strTrailingEnd = customStr.substring(0, (customStr.indexOf("Blog")));
String strTrailingEnd1 = customStr.substring((customStr.lastIndexOf("page")));
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(customStr);
stringBuilder.setSpan(new NonUnderlinedClickableSpan() {

@Override
public void onClick(View widget) {

Intent browse = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
startActivity(browse);
}
},strLeading.length(), 
strLeading.length() + strTrailing.length()+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

stringBuilder.setSpan(new NonUnderlinedClickableSpan() {

@Override
public void onClick(View widget) {

Intent browse = new Intent(Intent.ACTION_VIEW, Uri.parse(linkBlog));
startActivity(browse);
}
},strTrailingEnd.length(), 
strTrailingEnd.length() + strTrailingEnd1.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

text4.setText(stringBuilder);
text4.setMovementMethod(LinkMovementMethod.getInstance());
}

public class NonUnderlinedClickableSpan extends ClickableSpan {
@Override
public void updateDrawState(TextPaint ds) {

ds.setColor(Color.MAGENTA);
ds.setUnderlineText(false);
ds.setTypeface(Typeface.DEFAULT_BOLD);
}

@Override
public void onClick(View v) {

}
}

public static String getXMLString(Context context, int stringID) {

Resources res = context.getResources();
return res.getString(stringID);
}
}

main.xml file :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView android:id="@+id/text1" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textSize="20sp"
    android:text="@string/link"
    android:padding="15dip"/>

<TextView android:id="@+id/text2" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textSize="20sp"
     android:text="@string/bold_link"
    android:padding="15dip"/>
    
<TextView android:id="@+id/text3" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textSize="20sp"
    android:text="@string/link"
    android:padding="15dip"/>  
    
    
 <TextView android:id="@+id/text4" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textSize="20sp"
    android:text="@string/custom_link_text"
    android:padding="15dip"/>       
</LinearLayout>

string.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, SpannableStringActivity!</string>
    <string name="app_name">SpannableString</string>
    <string name="link"><a href="http://android2011dev.blogspot.com">Go to Android-Dev blog page.</a> </string>
    <string name="bold_link">
Go to 
<a STYLE="text-decoration:none" href="http://android2011dev.blogspot.com">
<b>Android Dev Blog</b>
</a> page.
</string>
<string name="custom_link_pre">Go to </string>
<string name="custom_link_end">Android Dev Blog </string>
<string name="custom_link_end_text">page.</string>
<string name="custom_link_text">Go to Google search page and Blog page.</string>
</resources>