Nurdin
Nurdin

Reputation: 23883

Android - Hashtag in TextView

How to implement hashtag inside TextView? What I want to do is implement linkable hashtag inside textview. Then user can click on it (hashtag) and switch to another fragment. This is my layout and fragment.

Layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainFragment" >

    <TextView
            android:id="@+id/txtHashtag"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Iena I #love you !!!"/>
</RelativeLayout>

Fragment

package com.xxxx;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.xxxxx.R;

public class MainFragment extends Fragment{

    private TextView txtHashtag;
    public MainFragment() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        View v = LayoutInflater.from(getActivity()).inflate(R.layout.activity_main_fragment,
                null);

        txtHashtag = (TextView) v.findViewById(R.id.txtHashtag);

        return v;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);
    }
}

Upvotes: 9

Views: 10074

Answers (4)

pRaNaY
pRaNaY

Reputation: 25312

Try below code to match TextView text that start with #:

...
txtHashtag = (TextView) v.findViewById(R.id.txtHashtag);
//Pattern to find if there's a hash tag in the message

            Pattern tagMatcher = Pattern.compile("[#]+[A-Za-z0-9-_]+\\b");      

            String url = "https://www.google.co.in/";
            //Attach Linkify to TextView
            Linkify.addLinks(txtHashtag, tagMatcher, url);
...

Upvotes: 3

Danylo Volokh
Danylo Volokh

Reputation: 4285

You can use this simple library HashTagHelper

It has very simple usage:

mHashTagText = (TextView) findViewById(R.id.text);
mTextHashTagHelper = HashTagHelper.Creator.create(getResources().getColor(R.color.colorPrimary), 
    new HashTagHelper.OnHashTagClickListener() {
        @Override
        public void onHashTagClicked(String hashTag) {

        }
});

// pass a TextView or any descendant of it (incliding EditText) here.
// Hash tags that are in the text will be hightlighed with a color passed to HasTagHelper

mTextHashTagHelper.handle(mHashTagText);

Upvotes: 15

Ibukun Muyide
Ibukun Muyide

Reputation: 1298

Use this, Clickable Span in TextView

// setting span

    SpannableString tagSpan = new SpannableString("#clickMe");
    ClickableSpan clickSpan = new ClickableSpan() {
        @Override
        public void onClick(View textView) {
            //code to swtich  to new fragment
        }
        @Override
        public void updateDrawState(TextPaint paint) {
            super.updateDrawState(paint);
            paint.setUnderlineText(true); // set underline if you want to underline
            paint.setColor(Color.BLUE); // set the color to blue
        }
    };
    tagSpan.setSpan(clickSpan, startPosition, endPosition, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

    TextView txtHashtag = (TextView) findViewById(R.id.txtHashtag);
    txtHashtag.setText(tagSpan);
    txtHashtag.setMovementMethod(LinkMovementMethod.getInstance());

You can implement more than one span in a textView, so simply write a function to do that and call it for each #HashTag

Upvotes: 3

Noor Azam
Noor Azam

Reputation: 15

Whatever view you want it to be reacting with clicks, you have to attach an onClickListener to it just like you implemented on button (assuming you have understood mechanics of button clicks).

therefore, it is possible to have it like this:

txtHashtag.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // This is where you call the method to change fragment
        }
    });

As for the method to go to the said fragment, ensure you have that fragment configured to receive parameters during instantiation as such:

public class HashtagViewFragment extends Fragment {
private static final String TAG = "HashtagViewFragment";
public static final String PARAM_HASHTAG = "hashtag_string";

private TextView txtPassedString;

private String receivedString;

public static HashtagViewFragment newInstance(String myHashtag) {
    HashtagViewFragment fragment = new HashtagViewFragment();
    Bundle args = new Bundle();
    args.putString(PARAM_HASHTAG, myHashtag);
    fragment.setArguments(args);
    return fragment;
}

public HashtagViewFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getArguments() != null) {
        receivedString = getArguments().getString(PARAM_HASHTAG);
    } else {
        receivedString = "";
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.HashtagViewFragment, container, false);

    txtPassedString = (TextView) view.findById(R.id.tv_hashtag);
    txtPassedString.setText(receivedString);

    return view;
}

@Override
public void onResume() {
    super.onResume();
}

@Override
public void onPause() {
    super.onPause();
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
}

@Override
public void onDetach() {
    super.onDetach();
}
}

then, your ViewPager adapter needs to be configured as such that it can instantiate the fragments on demand like so:

public class HashtagPagerAdapter extends FragmentStatePagerAdapter {
private Context mContext;
private ArrayList<String> hashtags = new ArrayList<>();

public HashtagPagerAdapter(FragmentManager fm, Context ctx) {
    super(fm);
    this.mContext = ctx;
}

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return new MainFragment();
        default:
            return HashtagViewFragment.newInstance(hashtags.get(position - 1));
    }
}

private void setHashtags(ArrayList<String> latestHashtags) {
    this.hashtags = latestHashtags;
    notifyDataSetChanged();
}

private ArrayList<String> getHashtags() {
    return this.hashtags;
}

@Override
public int getCount() {
    return hashtags.size() + 1;
}

}

Provided the ViewPager is public static in your FragmentActivity object, you can access it from your MainFragment like this:

MyFragmentActivity.myViewPager

With this in mind, you may now create the method to add and swap fragment as follows:

private void swapFragment() {
    ArrayList<String> currentHashtags = ((HashtagPagerAdapter)MyFragmentActivity.myViewPager.getAdapter()).getHashtags();
    currentHashtags.add(txtHashtag.getText().toString());
    ((HashtagPagerAdapter)MyFragmentActivity.myViewPager.getAdapter()).setHashtags(currentHashtags);
    MyFragmentActivity.myViewPager.setCurrentItem(currentHashtags.size(), true);
}

Upvotes: 0

Related Questions