Question

I have TextView with spans of type ClickableStringSpan defined as below:

public class ClickableStringSpan extends ClickableSpan {
    private View.OnClickListener mListener;
    int color;
    public ClickableStringSpan(View.OnClickListener listener,int color) {
        mListener = listener;
        this.color = color;

    }

    @Override
    public void onClick(View v) {
        mListener.onClick(v);
    }

       @Override public void updateDrawState(TextPaint ds) {
           super.updateDrawState(ds);
           ds.setUnderlineText(false);
           ds.setColor(color);
       }
}

I set clickable spans on my text like this:

spanStr.setSpan(new ClickableString(new linkedTextClickListener(), linkColor),
                        startIndex, endIndex,
                        SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);

Now I want to apply these string to EditTexts instead of TextViews. Everything is fine just Clickable strings are now not clicked anymore. I want to know how can I pass clicks on this sort of spans to their assigned clicklistener?

Update: My main concern to edit text is I want to allow user select some part of text and share it meanwhile he/she can click on ClickableSpans.

Was it helpful?

Solution

You need to set the TextView's/EditText's movement method to LinkMovementMethod to be able to get clicked links. Unfortunately that disables the ability to select text which works only if you set the movement method to ArrowKeyMovementMethod. http://developer.android.com/reference/android/text/method/LinkMovementMethod.html http://developer.android.com/reference/android/text/method/ArrowKeyMovementMethod.html

To solve this I created an custom MovementMethod class that inherits from ArrowKeyMovementMethod and adds the ability to click links. :

/**
 * ArrowKeyMovementMethod does support selection of text but not the clicking of links.
 * LinkMovementMethod does support clicking of links but not the selection of text.
 * This class adds the link clicking to the ArrowKeyMovementMethod.
 * We basically take the LinkMovementMethod onTouchEvent code and remove the line
 *      Selection.removeSelection(buffer);
 * which deselects all text when no link was found.
 */
public class EnhancedMovementMethod extends ArrowKeyMovementMethod {

    private static EnhancedMovementMethod sInstance;

    public static MovementMethod getInstance() {
        if (sInstance == null) {
            sInstance = new EnhancedMovementMethod ();
        }
        return sInstance;
    }

    @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) {
                    link[0].onClick(widget);
                }
                else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
                }

                return true;
            }
            /*else {
                Selection.removeSelection(buffer);
            }*/
        }

        return super.onTouchEvent(widget, buffer, event);
    }

}

All you need to do is set the movement method of your EditText and you're good to go:

yourEditTExt.setMovementMethod(EnhancedMovementMethod.getInstance());

The code above only works with unformatted text, meaning once you decide to format your text using text styles (bold, italic etc.) or different font sizes, it won't find the clicked link any more. I do have the code to deal with formatted text but since that wasn't part of the question I made the sample code as short as possible.

OTHER TIPS

The following code example should work for you, I have also tested and it gives you click events of ClickableSpanString

May be you have forgot to add setMovementMethod

    EditText spanEditText = (EditText)rootView.findViewById(R.id.edtEmailId);

    // this is the text we'll be operating on  
    SpannableStringBuilder text = new SpannableStringBuilder("World Super Power God LOVE");  

    // make "World" (characters 0 to 5) red  
    text.setSpan(new ForegroundColorSpan(Color.RED), 0, 5, 0); 

    // make "Super" (characters 6 to 11) one and a half time bigger than the textbox  
    text.setSpan(new RelativeSizeSpan(1.5f), 6, 11, 0);  

    // make "Power" (characters 12 to 17) display a toast message when touched  
    final Context context = getActivity().getApplicationContext();  
    ClickableSpan clickableSpan = new ClickableSpan() {  
        @Override  
        public void onClick(View view) {  
            Toast.makeText(context, "Power", Toast.LENGTH_LONG).show();  
        }  
    };  
    text.setSpan(clickableSpan, 12, 17, 0);  

    // make "God" (characters 18 to 21) struck through  
    text.setSpan(new StrikethroughSpan(), 18, 21, 0);  

    // make "LOVE" (characters 22 to 26) twice as big, green and a link to this site.  
    // it's important to set the color after the URLSpan or the standard  
    // link color will override it.  
    text.setSpan(new RelativeSizeSpan(2f), 22, 26, 0);  
    text.setSpan(new ForegroundColorSpan(Color.GREEN), 22, 26, 0);  

    // make our ClickableSpans and URLSpans work  
    spanEditText.setMovementMethod(LinkMovementMethod.getInstance());  

    // shove our styled text into the TextView          
    spanEditText.setText(text, BufferType.EDITABLE);
//try this way,hope this will help you...

**activity.xml** code
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

   <EditText
       android:id="@+id/edtText1"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:focusableInTouchMode="false"
       android:focusable="false"
       android:editable="false"/>

    <EditText
        android:id="@+id/edtText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusableInTouchMode="false"
        android:focusable="false"
        android:editable="false"/>

    <EditText
        android:id="@+id/edtText3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusableInTouchMode="false"
        android:focusable="false"
        android:editable="false"/>
</LinearLayout>

**Activity** code
    private EditText edtText1;
    private EditText edtText2;
    private EditText edtText3;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);
        edtText1 = (EditText) findViewById(R.id.edtText1);
        edtText2 = (EditText) findViewById(R.id.edtText2);
        edtText3 = (EditText) findViewById(R.id.edtText3);

        String string1 = "Demo EditText First";
        edtText1.setText(setSpanColor(string1, "First",R.color.orange,new SpannableClickListener(){
            @Override
            public void onClickListener(View view) {
                view.performClick();
            }
        }));

        edtText1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MyActivity.this,"EditText First Click",Toast.LENGTH_SHORT).show();
            }
        });


        String string2 = "Demo EditText Second";
        edtText2.setText(setSpanColor(string2, "Second",R.color.orange,new SpannableClickListener(){
            @Override
            public void onClickListener(View view) {
                view.performClick();
            }
        }));

        edtText2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MyActivity.this,"EditText Second Click",Toast.LENGTH_SHORT).show();
            }
        });


        String string3 = "Demo EditText Third";
        edtText3.setText(setSpanColor(string3, "Third",R.color.orange,new SpannableClickListener(){
            @Override
            public void onClickListener(View view) {
                view.performClick();
            }
        }));

        edtText3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MyActivity.this,"EditText Third Click",Toast.LENGTH_SHORT).show();
            }
        });

    }
    private SpannableStringBuilder setSpanColor(final String str,final String text,final int color,final SpannableClickListener listener) {
        SpannableStringBuilder ssb = new SpannableStringBuilder(str);

        if (str.contains(text)) {
            ssb.setSpan(new ClickableSpan() {
                @Override
                public void onClick(View view) {
                    listener.onClickListener(view);
                }

                @Override
                public void updateDrawState(TextPaint ds) {
                    ds.setColor(getResources().getColor(color));
                }
            }, str.indexOf(text), str.indexOf(text)
                    + text.length(), 0);
        }
        return ssb;

    }

    interface SpannableClickListener{
        public void onClickListener(View view);
    }
}

The above answers are helpful. Hope below will also help you:

    android:linksClickable="true"
    android:autoLink="web"

 val message: String = String.format(
        getString(R.string.message_content),
        firstNameEditText.text,
        lastNameEditText.text,
        dateTextView.text,
        timeTextView.text
    )

    val gMapURL = getString(R.string.google_map_location)

    // Setup my Spannable with clickable URLs
    val spannable: Spannable = SpannableString(gMapURL)
    Linkify.addLinks(spannable, Linkify.WEB_URLS)

    // Append a zero-width space to the Spannable
    val gText = TextUtils.concat(spannable, "\u200B")

    val finalText = TextUtils.concat(message, gText)
    messageContentEditText.setText(finalText)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top