How to set clickablespan on a Textview in RecyclerView

2k Views Asked by At

I am have recyclerviwq with textvies, and the text in the textview has urlss and I want to setclickablespan on the textview and capture the urls.

I am using this accepted answer and it's not working.

This is my code:

    public class LibAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context mContext;
    private List<LibItem> mLibItemList;

    private final int HEAD_VIEW = 0;
    private final int LIB_VIEW = 1;

    public LibAdapter(List<LibItem> libItems, Context context) {
        super();
        this.mLibItemList = libItems;
        this.mContext = context;
    }

    @Override
    public int getItemViewType(int position) {
        if (isPositionItem(position)) {
            return HEAD_VIEW;
        }
        return LIB_VIEW;
    }

    private boolean isPositionItem(int position) {
        return position == 0;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == LIB_VIEW) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.library_item, parent, false);
            return new LibHolder(view);
        } else  if (viewType == HEAD_VIEW) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.about_hedaer, parent, false);
            return  new HeadHolder(view);
        }
        return null;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof LibHolder) {
            final LibItem libItem = mLibItemList.get(position);
            ((LibHolder) holder).libName.setText(libItem.getLibName());
            ((LibHolder) holder).libCopy.setText(Html.fromHtml(libItem.getLibCopy()));
            ((LibHolder) holder).libLic.setText(mContext.getString(R.string.proj_license));

            setTextViewHTML(((LibHolder) holder).libWeb, mContext.getString(R.string.proj_code, libItem.getLibWebs()));
            ((LibHolder) holder).libLic.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d("LibAdapter", "License of " + libItem.getLibName() + "clicked");
                }
            });
        } else if (holder instanceof HeadHolder){
            String versionCode = BuildConfig.VERSION_NAME;
            ((HeadHolder) holder).abtVersion.setText(mContext.getString(R.string.app_version, versionCode));
        }
    }

    protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
    {
        int start = strBuilder.getSpanStart(span);
        int end = strBuilder.getSpanEnd(span);
        int flags = strBuilder.getSpanFlags(span);
        ClickableSpan clickable = new ClickableSpan() {
            public void onClick(View view) {
                Log.d("LipAdapter", span.getURL());
            }
        };
        strBuilder.setSpan(clickable, start, end, flags);
        strBuilder.removeSpan(span);
    }

    protected void setTextViewHTML(TextView text, String html)
    {
        CharSequence sequence = Html.fromHtml(html);
        SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
        URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
        for(URLSpan span : urls) {
            makeLinkClickable(strBuilder, span);
        }
        text.setText(strBuilder);
        text.setMovementMethod(LinkMovementMethod.getInstance());
    }



    @Override
    public int getItemCount() {
        return mLibItemList.size();
    }

    public class LibHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.lib_name) TextView libName;
        @BindView(R.id.lib_website) TextView libWeb;
        @BindView(R.id.lib_copyright) TextView libCopy;
        @BindView(R.id.lib_license) TextView libLic;

        public LibHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    public class  HeadHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.abt_version) TextView abtVersion;

        public HeadHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}

The text is set quite alright but the link refused to be clicked. please do you have a solution for this?

2

There are 2 best solutions below

2
On

You were trying this ::

  protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
    int start = strBuilder.getSpanStart(span);
    int end = strBuilder.getSpanEnd(span);
    int flags = strBuilder.getSpanFlags(span);
    ClickableSpan clickable = new ClickableSpan() {
        public void onClick(View view) {
            Log.d("LipAdapter", span.getURL());
        }
    };
    strBuilder.setSpan(clickable, start, end, flags);
    strBuilder.removeSpan(span);
}

But you need to do something like this::

protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
    int start = strBuilder.getSpanStart(span);
    int end = strBuilder.getSpanEnd(span);
    int flags = strBuilder.getSpanFlags(span);


    ClickableSpan clickable = new ClickableSpan() {
        @Override
        public void onClick(View widget) {
            Log.d("LipAdapter", span.getURL());
        }

        @Override
        public void updateDrawState(TextPaint ds) {
            super.updateDrawState(ds);
        }
    };

    strBuilder.setSpan(clickable, start, end, flags);
    strBuilder.removeSpan(span);
}

Hope it will work for others

0
On

I had the same issue and had to type-cast sequence to Spannable to make it work.

Just replace

SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);

with

Spannable strBuilder = (Spannable) sequence;