38

I have TextView with text that changed dynamically. This text contain strings like <a href='myWord'>myWord</a>. I want that after click to this "link" myWord appear in the EditText in the same activity.

This is my code:

txt.setText(Html.fromHtml("...<a href='link'>link</a>..."));
txt.setMovementMethod(LinkMovementMethod.getInstance());

It's work well for URLs inside href attribute, but there is an error for another format.

I found a lot of similar questions on the StackOverflow but all of them were about url links. In my app I want create "link" inside activity. In general, I can change tag to some another if it's depend...

Please help me! Thank you!

-----SOLVED----- Thank you Jacob Phillips for idea!

May it will be interesting someone in future. This is a code:

//This is my string;
String str = "<b>Text</b> which contains one <a href='#'>link</a> and another <a href='#'>link</a>";
//TextView;
TextView txt = new TextView(this);
//Split string to parts:                                        
String[] devFull = data[v.getId()][1].split("<a href='#'>");
//Adding first part:
txt.append(Html.fromHtml(devFull[0]));
//Creating array for parts with links (they amount always will devFull.length-1):
SpannableString[] link = new SpannableString[devFull.length-1];
//local vars:
ClickableSpan[] cs = new ClickableSpan[devFull.length-1];
String linkWord;
String[] devDevFull = new String[2];

for(int i=1; i<devFull.length; i++){
    //obtaining 'clear' link
    devDevFull = devFull[i].split("</a>");
    link[i-1] = new SpannableString(devDevFull[0]);
    linkWord = devDevFull[0];
    cs[i-1] = new ClickableSpan(){
        private String w = linkWord;
        @Override
        public void onClick(View widget) {
            // here you can use w (linkWord)
        }
    };
    link[i-1].setSpan(cs[i-1], 0, linkWord.length(), 0);
    txt.append(link[i-1]);
    try{
        txt.append(Html.fromHtml(devDevFull[1]));
    }
    catch(Exception e){}
}
lubart
  • 1,746
  • 3
  • 27
  • 35

6 Answers6

45

This should do the trick. Just change your edittext's text in the OnClickListener. It may be able to be reduced but this should work.

private void foo() {
    SpannableString link = makeLinkSpan("click here", new View.OnClickListener() {          
        @Override
        public void onClick(View v) {
            // respond to click
        }
    });

    // We need a TextView instance.        
    TextView tv = new TextView(context);   

    // Set the TextView's text     
    tv.setText("To perform action, ");

    // Append the link we created above using a function defined below.
    tv.append(link);

    // Append a period (this will not be a link).
    tv.append(".");

    // This line makes the link clickable!
    makeLinksFocusable(tv);
}

/*
 * Methods used above.
 */

private SpannableString makeLinkSpan(CharSequence text, View.OnClickListener listener) {
    SpannableString link = new SpannableString(text);
    link.setSpan(new ClickableString(listener), 0, text.length(), 
        SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
    return link;
}

private void makeLinksFocusable(TextView tv) {
    MovementMethod m = tv.getMovementMethod();  
    if ((m == null) || !(m instanceof LinkMovementMethod)) {  
        if (tv.getLinksClickable()) {  
            tv.setMovementMethod(LinkMovementMethod.getInstance());  
        }  
    }  
}

/*
 * ClickableString class 
 */

private static class ClickableString extends ClickableSpan {  
    private View.OnClickListener mListener;          
    public ClickableString(View.OnClickListener listener) {              
        mListener = listener;  
    }          
    @Override  
    public void onClick(View v) {  
        mListener.onClick(v);  
    }        
}
Jacob Phillips
  • 8,841
  • 3
  • 51
  • 66
  • Thank you for your answer. I'm sorry for may be stupid question, but what is the ClickableString() class? – lubart Apr 02 '12 at 10:06
  • I just added it. I used a modified version of [this answer](http://stackoverflow.com/a/5681946/884522) to a similar question – Jacob Phillips Apr 02 '12 at 19:16
  • Thank you! But it does not work :( I have an error on line `mListener.onClick(v);` in ClickableString class: `The method onClick(DialogInterface, int) in the type DialogInterface.OnClickListener is not applicable for the arguments (View)` and I don't know how to rectify it. Have you any ideas. Thank you anyway! – lubart Apr 02 '12 at 21:38
  • Solved! Thank you for idea! I used simple ClickableSpan() instead your ClickableString() and it's work fine! – lubart Apr 02 '12 at 23:05
  • You have to use `View.OnClickListener` rather than `DialogInterface.OnClickListener`. Please accept as answer :) – Jacob Phillips Apr 02 '12 at 23:24
  • Yes, I tried use `View.OnClickListener` but something was wrong. I used ClickableSpan() instead ClickableString() and it's helped. Thank you! – lubart Apr 02 '12 at 23:39
  • @JacobPhillips one little problem man. When you click the link it moves a little like it was "changed to visited" in a web page. getting smaller may be. Have a solution for that ? – MSaudi Dec 20 '14 at 19:24
18

Better approach is

   SpannableString ss = new SpannableString("Android is a Software stack");
    ClickableSpan clickableSpan = new ClickableSpan() {
        @Override
        public void onClick(View textView) {
            startActivity(new Intent(MyActivity.this, NextActivity.class));
        }
    };
    ss.setSpan(clickableSpan, 22, 27, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//where 22 and 27 are the starting and ending index of the String. Now word stack is clickable 
// onClicking stack it will open NextActiivty

    TextView textView = (TextView) findViewById(R.id.hello);
    textView.setText(ss);
    textView.setMovementMethod(LinkMovementMethod.getInstance());
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
3

You can use below code;

 SpannableString myString = new SpannableString(Html.fromHtml("Please "+"<font color=\"#F15d36\"><u>"+"login"+"</u></font>" +" or "+ "<font color=\"#F15d36\"><u>"+"sign up"+ "</u></font>"+" to begin your YupIT experience"));

        ClickableSpan clickableSpan = new ClickableSpan() {
            @Override
            public void onClick(View textView) {
                Toast.makeText(getContext(),"dfsgvdfs",Toast.LENGTH_SHORT).show();
            }
        };

        ClickableSpan clickableSpan1 = new ClickableSpan() {
            @Override
            public void onClick(View textView) {
                Toast.makeText(getContext(),"dfsgvdfs",Toast.LENGTH_SHORT).show();
            }
        };

        myString.setSpan(clickableSpan,6,12,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        myString.setSpan(clickableSpan1,15,23,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        myString.setSpan(new ForegroundColorSpan(Color.parseColor("#F15d36")),6, 12, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        myString.setSpan(new ForegroundColorSpan(Color.parseColor("#F15d36")),15,23, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);


        tvFound.setMovementMethod(LinkMovementMethod.getInstance());
        tvFound.setText(myString);
Vishal Vaishnav
  • 3,346
  • 3
  • 26
  • 57
0

To make it full answer with mixing answers;

private void textAreaInit()
{
    String str = "<a href='#'>Link 1</a> and <a href='#'>Link2</a> is here.";

    TextView tv = mConfirmText;  
    String[] devFull = str.split("<a href='#'>");


    tv.append(Html.fromHtml(devFull[0]));

    SpannableString[] link = new SpannableString[devFull.length-1];

    ClickableSpan[] cs = new ClickableSpan[devFull.length-1];
    String linkWord;
    String[] devDevFull = new String[2];

    for(int i=1; i<devFull.length; i++)
    {
        //obtaining 'clear' link
        devDevFull = devFull[i].split("</a>");
        link[i-1] = new SpannableString(devDevFull[0]);
        linkWord = devDevFull[0];
        final String a = linkWord;
        cs[i-1] = new ClickableSpan()
        { 
            private String w = a;
            @Override
            public void onClick(View widget) {

                if(w.equals("Link 1"))
                {
                    Intent intent = new Intent(PrintPropertiesActivity.this, ViewerAcivity.class);
                    intent.putExtra("title", "Link1");
                    intent.putExtra("uri", "link1");
                    intent.putExtra("type", "1");
                    startActivity(intent);
                }
                else
                {
                    Intent intent = new Intent(PrintPropertiesActivity.this, ViewerAcivity.class);
                    intent.putExtra("title", "Link2");
                    intent.putExtra("uri", "link2");
                    intent.putExtra("type", "2");
                    startActivity(intent);
                }
            }
        };
        link[i-1].setSpan(cs[i-1], 0, linkWord.length(), 0);
        tv.append(link[i-1]);
        try{
            tv.append(Html.fromHtml(devDevFull[1]));
        }
        catch(Exception e){}
    }


    makeLinksFocusable(tv);
}

private void makeLinksFocusable(TextView tv) {
    MovementMethod m = tv.getMovementMethod();  
    if ((m == null) || !(m instanceof LinkMovementMethod)) {  
        if (tv.getLinksClickable()) {  
            tv.setMovementMethod(LinkMovementMethod.getInstance());  
        }  
    }  
}
Berkay Turancı
  • 3,373
  • 4
  • 32
  • 45
0

The best workaround I know is to create your own Button class. You could make the Button have a transparent background so that only the text is seen by the user. Then when the Button is pressed down change the TextColor and TextStyle of the button to be a darker color and underlined. This will work exactly as a link does. You can then use startActivity to go to the appropriated activity. You should not use hyperlinks to connect to other activities within your application.

  • Thank you for your answer, but I can not use Button. Text inside my TextView is not static and I can not know where my "link" will appear on the next time. Text comes from DB and I need to mark my linkWord in some way. I'm using tag... – lubart Apr 02 '12 at 01:18
0

My personal opinion would be to make a second textview containing the text that you want to be your link. Then you could do your action in the onClick of this second textView . Also as zzzzzzzzzzz stated above, you could choose to change the font properties of that text to whatever you want once it has been clicked.

testingtester
  • 528
  • 4
  • 11
  • 1
    Thank you for your answer, but I can not divide my TextView for few peaces, I need one hole TextView... – lubart Apr 02 '12 at 01:21
  • In order to really make an inner-Application link (which is what you want if I understand correctly), I think the only way to do it is call the OnClick method and I don't think that is possible to do on a specific part of a textview. Best of luck with it though – testingtester Apr 02 '12 at 01:29