Android TextView Hyperlink Implementation _android

Source: Internet
Author: User
Tags gettext static class

Hyperlinks in TextView can be implemented in several ways:
First, html.fromhtml way

TextView, in itself, supports part of the HTML format tag. This includes commonly used font size color settings, text links, and so on. It's also easier to use, just use the Html class to convert: Textview.settext (html.fromhtml (str));

The code is as follows:

 public class Test10activity extends activity {
  TextView TextView;
  @Override
  protected void onCreate (Bundle savedinstancestate) {
   super.oncreate (savedinstancestate);
   Setcontentview (r.layout.activity_test10);
   TextView = (TextView) Findviewbyid (r.id.text);
   String weblinktext = "<a href= ' https://souly.cn ' > HTML hyperlink Test </a>";
   Textview.settext (html.fromhtml (Weblinktext));
  }
 
 

When you click the hyperlink and there is no jump effect, you need to add

Textview.setmovementmethod (Linkmovementmethod.getinstance ());
before they jump. Clicking on this will open the URL with the default browser.

Now the font color and underline are the default styles, and modifying the font color is simpler and can be directly labeled:

 String Weblinktext =
   "<font color= ' #333333 ' ><a href= ' https://souly.cn '" style= "text-decoration:none; Color: #0000FF ' >
   HTML hyperlink Test </a> ';
  

But there is no way to remove the underline without resorting to other classes.

An easier way to do this is to add Autolink to the TextView XML layout, which is easiest to do, but cannot modify the style:

<textview
   android:id= "@+id/text"
   android:layout_width= "Wrap_content"
   Wrap_content "
   android:textsize=" 20sp "
   android:text=" souly.cn "android:autolink=" Email|phone|web "
   />  

Second, Spannable Way

After the android:autolink= "Email|phone|web" is set in the XML, there is an underscore underneath the URL text, and we can see the source code of the class Clickablespan class inherited by Urlspan, as follows:

Public abstract class Clickablespan extends Characterstyle implements Updateappearance {

   /
   * Performs the click AC tion associated with this span.
   * * Public

   abstract void OnClick (View widget);

   /
   * makes the text underlined and in the link color.
   * *

   @Override public

   void Updatedrawstate (Textpaint ds) {

    ds.setcolor (ds.linkcolor);

    Ds.setunderlinetext (True);

   }

  

It calls Ds.setunderlinetext (true); The underline is set. We can then set a Spannable object without an underscore. We rewrite a class to inherit Underlinespan, and like Clickablespan, are characterstyle subclasses.

Use the following methods:

 public class Test10activity extends activity {TextView TextView;
  @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
  Setcontentview (R.LAYOUT.ACTIVITY_TEST10);
  TextView = (TextView) Findviewbyid (R.id.text);
  String weblinktext = "my blog-->https://souly.cn";
  Textview.settext (Weblinktext);
  Nounderlinespan Mnounderlinespan = new Nounderlinespan ();
   if (Textview.gettext () instanceof spannable) {spannable s = (spannable) textview.gettext ();
  S.setspan (Mnounderlinespan, 0, S.length (), Spanned.span_mark_mark); The public static class Nounderlinespan extends Underlinespan {public nounderlinespan () {} public Nounderlinespan (P
   Arcel src) {} @Override public void Updatedrawstate (Textpaint ds) {super.updatedrawstate (DS);
  Ds.setunderlinetext (FALSE); }
 }
}

So textview in the interface will not be underlined, but it retains the function of Autolink. This hyperlink is the default color and if you need to change the color you can set the android:textcolorlink= "#1e84fb" in the XML, or set Tv.setlinktextcolor (color) in the Java code;

The above example is the Autolink set in the case of automatic recognition of hyperlinks, if you do not need to automatically identify, but you manually set the URL to jump, you can use the following methods, first delete the XML android:autolink= "Email|phone|web"

public class Test10activity extends activity {
 TextView TextView;
 @Override
 protected void onCreate (Bundle savedinstancestate) {
  super.oncreate (savedinstancestate);
  Setcontentview (r.layout.activity_test10);
  TextView = (TextView) Findviewbyid (r.id.text);
  String weblinktext = "my blog";
  spannablestring Text = new spannablestring (weblinktext);
  Nounderlinespan Mnounderlinespan = new Nounderlinespan ("https://souly.cn");
  Text.setspan (Mnounderlinespan,0,text.length (), spanned.span_exclusive_exclusive);
  Textview.settext (text);
  Textview.setmovementmethod (Linkmovementmethod.getinstance ());
 }
 public static class Nounderlinespan extends Urlspan {public
  nounderlinespan (String url) {
   super (URL);
  }
  @Override public
  void Updatedrawstate (Textpaint ds) {
   super.updatedrawstate (DS);
   Ds.setunderlinetext (FALSE);}}

The Nounderlinespan here inherits the Urlspan rather than the Underlinespan,urlspan is the Clickablespan subclass.

Sometimes we need to customize hyperlink Click events, such as playing a toast, then rewrite Clickablespan:

public class Test10activity extends activity {TextView TextView;
  @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
  Setcontentview (R.LAYOUT.ACTIVITY_TEST10);
  TextView = (TextView) Findviewbyid (R.id.text);
  String weblinktext = "my Blog";
  spannablestring spstr = new spannablestring (weblinktext); Clickablespan Clickspan = new Nolineclickspan (spstr.tostring ());
  Set Hyperlink Spstr.setspan (Clickspan, 0, Spstr.length (), spanned.span_inclusive_exclusive);
  Textview.append (SPSTR);
 Textview.setmovementmethod (Linkmovementmethod.getinstance ());
  Private class Nolineclickspan extends Clickablespan {String text;
   Public Nolineclickspan (String text) {super ();
  This.text = text;
   @Override public void Updatedrawstate (Textpaint ds) {ds.setcolor (ds.linkcolor); Ds.setunderlinetext (FALSE); Remove underline} @Override public void OnClick (View widget) {processhyperlinkclick (text);//click Hyperlink to call} private VO ID ProceSshyperlinkclick (String text) {Toast.maketext (This,text,toast.length_short). Show ();
 }
}

Three, Linkify.addlinks Way

In addition to using schemas such as the default Web, we can add custom patterns by Linkify the Addlinks method of the class. Linkify.addlinks is also one of the most powerful ways to function.

Before talking about this way, we should first popularize the knowledge of intent filters.

Activity,service,broadcast receivers in Android can set intent filters that can have one or more intent filters. Each filter describes a component's ability to tell what implicit intent the system can handle. An explicit intent is always able to pass to its target component, regardless of what it contains; But an implicit intent can be passed to it only if it can pass through one of the components ' filters.

An intent filter is an instance of a Intentfilter class. Because the Android system must know its capabilities before starting a component, intent filters are not usually set in Java code, but are set in the application's manifest file (androidmanifest.xml). With one exception, the filter for the broadcast receiver dynamically registers by calling Context.registerreceiver (), which creates a Intentfilter object directly.

A filter has fields that correspond to the actions, data, and kinds of intent objects. Filters to detect all three fields of implicit intent, any of which fail, the Android system will not pass intent to the component. However, because a component can have multiple intent filters, a intent filter is detected, and other filters may be detected by the device.

* Motion Detection

The elements in the manifest file list actions with child elements, such as:

<intent-filter>
 <action android:name= "Com.example.project.SHOW_CURRENT"/>
 <action Android : Name= "Com.example.project.SHOW_RECENT"/>
 <action android:name= "Com.example.project.SHOW_PENDING"/ > ...
</intent-filter>

As the example shows, although a intent object is only a single action, a filter can list more than one. This list cannot be empty, a filter must contain at least one child element, or it will block all intents.

To detect, the action specified in the intent object must match one of the filters ' action lists. If an object or filter does not specify an action, the result is as follows:

If the filter does not specify an action, none of the intent will match, and all intent will detect failure, that is, no intent can pass through the filter. If the intent object does not specify an action, it is automatically checked (as long as the filter has at least one child element, otherwise it is the case above).

* Kind of Detection

Similarly, the elements in the manifest file are listed by child elements, such as:

<intent-filter>
 <category android:name= "Android.intent.category.DEFAULT"/>
 <category Android:name= "Android.intent.category.BROWSABLE"/> ...
</intent-filter>

For a intent to be detected by species, each type in the intent object must match one of the filters. That is, the filter can list the additional kinds, but the intent object must be able to find in the filter, as long as a species in the filter list does not, even if the kind of detection failure!

Therefore, in principle, if a intent object does not have a category (that is, a kind of character blank) it should always be tested by kind, regardless of the type of filter. With one exception, Android treats all implicit intent that are passed to context.startactivity () as if they contain at least "Android.intent.category.DEFAULT" (corresponding Category_ Default constant). Therefore, an activity that wants to receive an implicit intent must include "Android.intent.category.DEFAULT" in the intent filter.

Note: the "Android.intent.action.MAIN" and "Android.intent.category.LAUNCHER" settings, which mark the activity to start a new task and take to the Startup list interface respectively. They can contain "Android.intent.category.DEFAULT" to a list of categories, or they may not be included.

* Data detection

Similarly, the elements in the manifest file list data in child elements, such as:

<intent-filter>
  <data android:mimetype= "video/mpeg" android:scheme= "http"/>
  <data android: Mimetype= "audio/mpeg" android:scheme= "http"/>
  ...
</intent-filter>

Each element specifies a URI and data type (MIME type). It has several properties scheme, host, port, path, query, and fragment correspond to each part of the URI: Scheme://host:port/path?query#fragment or scheme:// Userinfo@host:port/path?query#fragment.

Scheme is Content,host is "Com.example.project", Port is 200,path is "folder/subfolder/etc". The host and port form the credential (authority) of the URI, and port is ignored if the host does not specify it. These attributes are optional, but not all of them are completely independent. To make authority meaningful, scheme must also be specified. To make the path meaningful, both scheme and authority must be specified.

When you compare the URI of a intent object and a filter, only the URI attributes that appear in the filter are compared. For example, if a filter only specifies scheme, all URIs that have this scheme match the filter, and if a filter specifies scheme and authority, but no path is specified, all URIs matching scheme and authority are detected by , regardless of their path, and if several attributes are specified, matching is a match. However, the path in the filter can contain wildcard characters that require matching a part of the path.

The Type property of the element specifies the MIME types of the data. Both the intent object and the filter can match the subtype field with the wildcard character, such as "text/", and "audio/*" represents any subtype.

Data detection is necessary to detect both URIs and data types. The rules are as follows:

1. A Intent object contains neither a URI nor a data type: it cannot pass the test only if the filter does not specify any URIs or data type; 2. A Intent object contains a URI, but does not contain a data type: only if the filter also does not specify a data type, and their URI matches, can pass detection. For example, mailto: and Tel: Do not specify actual data. 3. A Intent object contains a data type but does not contain a URI: only if the filter contains only the data type and is the same as the intent, the detection is passed. 4. A Intent object contains both a URI and a data type (or a data type can be inferred from a URI): The data type part, which is passed only if it matches one of the filters; the URI part, its URI appears in the filter, or it has content: or File:uri, Or the filter does not specify a URI. In other words, if its filter lists only data types, the component assumes support for content: and file:. If a intent can pass through more than one activity or service filter, the user may be asked if the component is activated. If no target is found, an exception is generated.

Let's write an example to receive a specific URI to open an activity by defining scheme

The first is to set the following parameters for the activity of Androidmanifast.xml to be specified scheme

    <intent-filter>

        <category android:name= "Android.intent.category.DEFAULT" ></category>

        <action android:name= "Android.intent.action.VIEW" ></action>

        <data android:host= "Profile" Android:scheme= "MXN"/>
    </intent-filter>

This specifies that scheme of the receiving URI is "MXN", the host is "profile" and the action is the intent of view. You can use the following Intent to invoke Activity:startactivity (new Intent (Intent.action_view, Uri.parse ("mxn://profile?uid=1")); Pass a parameter uid=1.

Accept parameters in an activity that has filter set:

public class Test9activity extends activity {
  private String uid;
  private static final Uri Profile_uri = Uri.parse ("Mxn://profile");
  @Override
  protected void onCreate (Bundle savedinstancestate) {
    super.oncreate (savedinstancestate);
    Setcontentview (R.LAYOUT.ACTIVITY_TEST8);
    Extractuidfromuri ();
  }
  private void Extractuidfromuri () {
    uri uri = getintent (). GetData ();
    if (URI!= null && profile_uri.getscheme (). Equals (Uri.getscheme ())) {
      uid = uri.getqueryparameter ("UID");
      log.d ("=====", "UID from URL:" + uid);
    }
  }

Following the use of linkify to implement hyperlinks to achieve the micro-blog @ HYPERLINK function, the layout file is as follows

<relativelayout
     xmlns:android= "http://schemas.android.com/apk/res/android"
     xmlns:tools= "http:// Schemas.android.com/tools "
     android:layout_width=" match_parent "
     android:layout_height=" Match_parent "
     android:gravity= "center"
     > 

       <textview
         android:id= "@+id/text"
         android:layout_width= " Wrap_content "
         android:layout_height=" wrap_content "
         android:textsize=" 20sp "
         android:text=" " Google's parent company Alphabet the market value of Super Apple: The world's first "according to foreign media reports, @ Google parent company @Alphabet
         through the company split and search advertising business continued strong, share prices continue to climb. U.S. time in Monday, Alphabet's company market capitalisation has surpassed the @ Apple,
         becomes the world market value biggest company. www.google.com "
         />
   </RelativeLayout>

When you need to make a custom pattern and a built-in schema web,phone to be recognized together, it is important to declare the built-in schema and then declare the custom schema, and you cannot declare the Autolink property in the XML, otherwise the custom pattern will not work. Because when you set up a built-in mode, you delete the existing schema first. The following user name with a regular match with "@" is used, and then passed as a UID to the next page:

public class Test10activity extends activity {
  TextView TextView;
  @Override
  protected void onCreate (Bundle savedinstancestate) {
    super.oncreate (savedinstancestate);
    Setcontentview (r.layout.activity_test10);
    TextView = (TextView) Findviewbyid (r.id.text);
    Pattern p = pattern.compile (@ (\w+?) (? =\w|$) (.)");
    Linkify.addlinks (TextView, p, "mxn://profile?uid=");
  }

Receive the same time as above:

public class Test9activity extends activity {
  private String uid;
  private static final Uri Profile_uri = Uri.parse ("Mxn://profile");
  @Override
  protected void onCreate (Bundle savedinstancestate) {
    super.oncreate (savedinstancestate);
    Setcontentview (R.LAYOUT.ACTIVITY_TEST8);
    Extractuidfromuri ();
  }
  private void Extractuidfromuri () {
    uri uri = getintent (). GetData ();
    if (URI!= null && profile_uri.getscheme (). Equals (Uri.getscheme ())) {
      uid = uri.getqueryparameter ("UID");
      log.d ("=====", "UID from URL:" + uid);
    }
  }

The effect is as follows:

As you can see in the above diagram, www.google.com is not recognized as a link (because we have not set up Web mode). It is important to note that when you need to make custom patterns and built-in schema Web,phone, you must declare the built-in schema and then declare the custom schema, and you cannot declare it in XML by Autolink property, otherwise the custom pattern will not work. Because when you set up a built-in mode, you delete the existing schema first.

Change the Java code above to:

public class Test10activity extends activity {
  TextView TextView;
  @Override
  protected void onCreate (Bundle savedinstancestate) {
    super.oncreate (savedinstancestate);
    Setcontentview (r.layout.activity_test10);
    TextView = (TextView) Findviewbyid (r.id.text);
    Pattern p = pattern.compile (@ (\w+?) (? =\w|$) (.)");
    Linkify.addlinks (TextView, linkify.web_urls);
    Linkify.addlinks (TextView, p, "mxn://profile?uid=");
  }
 

You can now recognize both the Web and custom mode.

Again, this hyperlink is the default color, and if you need to change the color you can set the android:textcolorlink= "#1e84fb" in the XML, or set Tv.setlinktextcolor (color) in the Java code;

When the hyperlink is still underlined, if you want to remove it, or use the above ideas, rewrite Urlspan,

public class Test10activity extends activity {TextView TextView;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
    Setcontentview (R.LAYOUT.ACTIVITY_TEST10);
    TextView = (TextView) Findviewbyid (R.id.text); Pattern Mentionspattern = Pattern.compile ("@ (\w+?) (? =\w|$)
    (.)");
    String mentionsscheme = String.Format ("%s/?%s=", "Mxn://profile", "UID");
    Linkify.addlinks (TextView, linkify.web_urls);
    Linkify.addlinks (TextView, Mentionspattern, Mentionsscheme);
  Stripunderlines (TextView);
    Private class Urlspannounderline extends Urlspan {public urlspannounderline (String URL) {super (URL);
      @Override public void Updatedrawstate (Textpaint ds) {super.updatedrawstate (DS);
    Ds.setunderlinetext (FALSE);
    } private void Stripunderlines (TextView TextView) {spannable s = (spannable) 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);
 }
}

Linkify also supports Tranformfilter and Matchfilter interfaces. They provide additional control over the target URI and define matching strings, which are shown in the following framework code: Linkify.addlinks (Mytextview, pattern, Prefixwith, New Mymatchfilter (), New Mytransformfilter ());

Using Match Filter

Implement the Acceptmatch method in your defined Matchfilter to add additional criteria for regex style matching. When a potential match is found, the acceptmatch is triggered, and the matching start and end points (including the entire text being searched) are passed in as arguments. The next code shows a Matchfilter implementation that cancels any previous "." The end of the match.

Class Mymatchfilter implements Matchfilter {public
     boolean acceptmatch (charsequence s, int start, int end) {
      Retu RN S.charat (end-1)!= '. ';
     }
  }

Using Transform Filter

Transform Filter provides greater freedom for formatting text strings, allowing you to modify implicit URIs that are automatically generated by link text. Reducing the coupling between the link text and the target URI makes it more freely possible to decide how to display the data string to the user.

Using transform Filter, you implement the Transformurl method in the transformfilter you define. When Linkify finds the correct match, it invokes Transformurl, passing in the Regex style used and the default URI string it creates. You can modify the matching string, and then return a URI appropriate to the other Android application. The modification of transform filter can be realized by clicking the user name, passing the function of the user ID, returning the content you need to pass in the Transformurl

The following Transformfilter implementation converts the matching text to a lowercase URI:

Class Mytransformfilter implements Transformfilter {public
    string Transformurl (Matcher match, String URL) {
      return Url.tolowercase ();
  }

Now that we add match filter and transform filter, the above code can be modified as follows:

public class Test10activity extends activity {TextView TextView;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
    Setcontentview (R.LAYOUT.ACTIVITY_TEST10);
    TextView = (TextView) Findviewbyid (R.id.text); Pattern Mentionspattern = Pattern.compile ("@ (\w+?) (? =\w|$)
    (.)");
    String mentionsscheme = String.Format ("%s/?%s=", "Mxn://profile", "UID");
Linkify.addlinks (TextView, linkify.web_urls);
    Linkify.addlinks (TextView, Mentionspattern, Mentionsscheme); Linkify.addlinks (TextView, Mentionspattern, Mentionsscheme, New Linkify.matchfilter () {@Override public Boole
      An Acceptmatch (charsequence s, int start, int end) {return S.charat (end-1)!= '. '
        }, New Linkify.transformfilter () {@Override public string Transformurl (Matcher match, string url) {
      return Url.tolowercase ();
    }
    });
  Stripunderlines (TextView); } Private Class UrlspannounderliNE extends Urlspan {public urlspannounderline (String URL) {super (URL);
      @Override public void Updatedrawstate (Textpaint ds) {super.updatedrawstate (DS);
    Ds.setunderlinetext (FALSE);
    } private void Stripunderlines (TextView TextView) {spannable s = (spannable) 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);

 }
}

The above is the entire content of this article, I hope to help you learn.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.