I am using custom class (which extends over clickable span) to link all tags in a text view and highlight them.
I use the following code to set span:
SpannableString commentsContent = new SpannableString(message);
.....Some code ....
commentsContent.setSpan(new StringUtils.Hashtag(context),
hashTagStart,
hashTagEnd, 0);
where Hashtag Class looks this:
public static class Hashtag extends ClickableSpan{
Context context;
TextPaint textPaint;
public Hashtag(Context ctx) {
super();
context = ctx;
}
#Override
public void updateDrawState(TextPaint ds) {
Typeface tf = Typeface.create(("fonts/Lato-Regular.ttf"),Typeface.NORMAL);
ds.setTextSize(30); //TODO: Text size
ds.setColor(R.color.primary_dark);
ds.setAntiAlias(true);
ds.setTypeface(tf);
}
#Override
public void onClick(View widget) {
//Do something on click
}
The output(textview in the center) is something like this:
I want the hashtag spans to be highlighted like this:
The background color will be dynamically assigned. How can I achieve the desired effect?
EDIT 1:
This has to be used in a listview or recycler view. Thus, performance is also a parameter.
Related
I would like to link some text on a TextView to an Activity. This is the TextView that I have:
<TextView
android:id="#+id/termsLink"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/terms"
android:layout_weight="4"/>
where #string/terms is:
<string name="terms">Accept terms & conditions..</string>
If I had a link to a webpage I would do it like this:
TextView link = (TextView) findViewById(R.id.termsLink);
link.setMovementMethod(LinkMovementMethod.getInstance());
but I do not know how to start an Activity when I press the link as when it is a real link (that it links a webpage).
EDIT: Please note that I do not have to handle the onClick event in the full text because the link is only on the part "terms & conditions".
EDIT 2: I have tried using two TextView as suggested on the comments and one of the answers below to make the same effect. But sometimes (depending on the screen) the "terms & conditions" part occupy two lines because it does not fill properly on the available space so the second line it is shown on the second TextView and not on the begining of the second line.
The effect is similar to this:
Accept terms &
conditions.
and I would like that it would be like this:
Accept terms &
conditions.
Thanks in advance!
Create a helper class with inner onClick listener
public class ClickSpan extends ClickableSpan {
private String url;
private OnClickListener listener;
public ClickSpan(String url, OnClickListener listener) {
this.url = url;
this.listener = listener;
}
#Override
public void onClick(View widget) {
if (listener != null) listener.onClick(url);
}
public interface OnClickListener {
void onClick(String url);
}
}
Then convert existing span into clickable one
public static Spannable createClickableSpans(Spanned original, ClickSpan.OnClickListener listener) {
SpannableString result = new SpannableString(original);
URLSpan[] spans = result.getSpans(0, result.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = result.getSpanStart(span);
int end = result.getSpanEnd(span);
int flags = result.getSpanFlags(span);
result.removeSpan(span);
result.setSpan(new ClickSpan(span.getURL(), listener), start, end, flags);
}
return result;
}
So, final usage would be like
TextView link = (TextView) findViewById(R.id.termsLink);
link.setMovementMethod(LinkMovementMethod.getInstance());
link.setText(createClickableSpans((Spanned)link.getText(), new ClickSpan.OnClickListener(){
#Override
public void onClick(String url){
//Handle URL on text view click
}
}));
To make only part of a TextView clickable, you can use a spannable inside the TextView and set an onClick event listener. From here, you launch the activity with an intent as usual. You can limit the clickable section of the text by specifying the character positions (start to end)
Checkout this answer by #becomputer06
How to set the part of the text view is clickable
You should probably separate the text into 2 text views one with the terms and condition and one with just the accept.It would make things cleaner and easier. The following TextView is assuming its just for accept.
In the layouts corresponding java class(example: activity_main -> MainActivity):
public void start_activity(View view){
Intent newActivityIntent = new Intent(this,NewActivity.class);
startActivity(newActivityIntent);
}
NewActivity.class is just the name of the activity you want to start.
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
....
}
public void start_activity(View view){
.....
}
}
I'm using Mariotti's CardsLib to create a list with Cards. I create cards (in a for loop) as shown below:
CustomCard aCard = new CustomCard(getActivity().getApplicationContext());
CardHeader aHeader = new CardHeader(getActivity().getApplicationContext());
aHeader.setTitle(item.getHeaderText());
aCard.addCardHeader(aHeader);
aCard.setSpannableMainTitle(true);
aCard.setmSsbTitle(CustomSpannableBuilderForHome.getSpannedText(item));
CardThumbnail thumbnail = new CardThumbnail(getActivity().getApplicationContext());
thumbnail.setDrawableResource(R.drawable.ic_launcher);
aCard.addCardThumbnail(thumbnail);
cards.add(0, aCard);
CustomCard is a class extending Card class. I created this class because I need to assign an SpannableStringBuilder instance, instead of simple String. This is CustomCard:
public class CustomCard extends Card {
protected boolean isSpannableMainTitle;
/**
* Main Title
*/
protected SpannableStringBuilder mSsbTitle;
public SpannableStringBuilder getmSsbTitle() {
return mSsbTitle;
}
public void setmSsbTitle(SpannableStringBuilder mSsbTitle) {
this.mSsbTitle = mSsbTitle;
}
public boolean isSpannableMainTitle() {
return isSpannableMainTitle;
}
public void setSpannableMainTitle(boolean isSpannableMainTitle) {
this.isSpannableMainTitle = isSpannableMainTitle;
}
public CustomCard(Context context) {
super(context);
}
#Override
public void setupInnerViewElements(ViewGroup parent, View view) {
//Add simple title to header
if (view != null) {
TextView mTitleView = (TextView) view.findViewById(R.id.card_main_inner_simple_title);
if (mTitleView != null)
{
mTitleView.setText(isSpannableMainTitle? mSsbTitle : mTitle);
if (isSpannableMainTitle) mTitleView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
}
Everything worked fine prior to using maps api V2. Today, the card's title does not appear when the text does not contain spans. If it does have spans, only spans are shown. It is also worth mentioning that the title to be set, is ALWAYS an instance of SpannableStringBuilder.
For example:
Text1 = This is a text with no spans
Text2 = This is a (text) with (spans) <--- where () denote the presence of span.
This is the output:
Card 1:
Picture + Header + no text
Card 2:
Picture + Header + (text) (spans)
That is, the first card has no text, while the latter displays only spanned text (i.e. This is a with, all of them ignored).
As I said, this behavior started once I included Maps API V2. Please help!
I Want to create mulitple TextView dynamically in ListView item. suppose i use LinearLayout it will create textview horizontal or vertically. I want multiple textview with the wraping. How can i create like that please share your valuable ideas,
Below screen images.
Note :
Each textview have the click action
Mike voted 8 , lara voted 9 like that individual text with wraping conetxt.
I have a custom view (merge xml) that contains a text view (originally it's a more complicated view).
My custom view class like this
public class Example extends LinearLayout {
protected Context context;
protected TextView titleView;
public Example(Context context) {
super(context);
this.context = context;
LayoutInflater inflater = (LayoutInflater) `enter code here`context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.bloghu_title_layout, this, true);
this.setOrientation(LinearLayout.VERTICAL);
titleView = (TextView) getChildAt(0);
}
public void setBlogTitle(String blogTitle, final String blogUrl, String author, final String authorUrl) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
spannableStringBuilder.append(blogTitle.toUpperCase());
spannableStringBuilder.append(" / ");
spannableStringBuilder.setSpan(new RelativeSizeSpan(1.5f), 0, blogTitle.length() + 2, 0);
spannableStringBuilder.append(author);
spannableStringBuilder.setSpan(new RelativeSizeSpan(1.2f), spannableStringBuilder.length() - author.length(), spannableStringBuilder.length(), 0);
spannableStringBuilder.setSpan(new NonUnderlineClickableSpan() {
#Override
public void onClick(View widget) {
Log.d("span", blogUrl);
}
}, 0, blogTitle.length(), 0);
spannableStringBuilder.setSpan(new NonUnderlineClickableSpan() {
#Override
public void onClick(View widget) {
Toast.makeText(context, authorUrl, Toast.LENGTH_SHORT).show();
}
}, spannableStringBuilder.length() - author.length(), spannableStringBuilder.length(), 0);
spannableStringBuilder.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.index_orange)), 0, blogTitle.length(), 0);
spannableStringBuilder.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.black)),
spannableStringBuilder.length() - author.length(), spannableStringBuilder.length(), 0);
titleView.setMovementMethod(LinkMovementMethod.getInstance());
titleView.setText(spannableStringBuilder, BufferType.SPANNABLE);
}
}
The NonUnderlineClickableSpan() is an extended ClickAbleSpan(), it just because I don't want to underline the clickable text, end it has an empty onclick method that you have to override:
public class NonUnderlineClickableSpan extends ClickableSpan{
#Override
public void updateDrawState(TextPaint ds) {
ds.setColor(ds.linkColor);
ds.setUnderlineText(false); // set to false to remove underline
}
#Override
public void onClick(View widget) {
// TODO Auto-generated method stub
}
As you can see in Example class you can set a new NonUnderlineClickableSpan, in its' onClick() method you can set what to happen, than you have to set the first and the last character of the clickable span, and a flag (this is the last parameter, in this case 0).
Whit ForegroundSpan you can set font color, whith relative size span you can set different text sizes, and there are a lot of span to style your text and make it interactive, but it is a very under-documented part of android.
I haven't found a good tutorial about this topic yet, so if somebody know one, pls let me know :).
What is the problem, whit textviews in linearLayout? But I think, what you really looking for is spannable string,in this case you can set the formats (colour, font size, style and what ever you want, and onClick actions for every word, and you need just one text view.
I have added links to text that is surrounded by [square brackets] in a popup dialog box. The links however, are not clickable (nothing happens when they are pressed). I can't work out why(!)
Here is my dialog box activity:
public void popupDefinition(CharSequence term, LinkedHashMap<String, String> dictionaryMap){
SpannableString definition = new SpannableString(dictionaryMap.get(term)); // grab the definition by checking against the dictionary map hash
Linkify.addLinks(definition, pattern, scheme); // find text in square brackets, add links
AlertDialog alertDialog = new AlertDialog.Builder(ListProjectActivity.this).create(); // create a dialog box
alertDialog.setMessage(definitionFormatted); // set dialog box message
alertDialog.show(); // actually display the dialog box
}
'scheme' and 'pattern' are defined earlier, as follows:
final static Pattern pattern = Pattern.compile("\\[[^]]*]"); // defines the fact that links are bound by [square brackets]
final String scheme = "http://example.com/"; // THIS IS NOT WORKING
Why, when I tap the links that appear (they appear nicely underlined in blue), do they not cause any response?
I'm not actually trying to launch URL links (I'll be redirecting the ACTION_VIEW intent when it does occur), but I need to confirm that some sort of response is happening before I get to that...
I'm not actually trying to launch URL links
Since you don't need to use URLs, don't bother with trying to create a custom Linkify scheme since it only creates URLSpans. You simply want to start an Activity from a keyword in a TextView. As I stated in one of your similar, but not duplicate, questions I would use a custom span, introducing ActivitySpan:
public class ActivitySpan extends ClickableSpan {
String keyword;
public ActivitySpan(String keyword) {
super();
this.keyword = keyword;
}
#Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, AnotherActivity.class);
intent.putExtra("keyword", keyword);
context.startActivity(intent);
}
}
There are no bells or whistles here, this span takes a [keyword] that you surrounded in brackets and passes it to the another Activity.
While I don't like the idea of using Linkify because of URLSpans, its pattern matching and span creation is great, so I copied and modified it:
private void addLinks(TextView textView, Pattern pattern) {
SpannableString spannable = SpannableString.valueOf(textView.getText());
Matcher matcher = pattern.matcher(spannable);
// Create ActivitySpans for each match
while (matcher.find())
spannable.setSpan(new ActivitySpan(matcher.group()), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Set new spans in TextView
textView.setText(spannable);
// Listen for spannable clicks, if not already
MovementMethod m = textView.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
if (textView.getLinksClickable()) {
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
As a note, this method doesn't remove the [brackets] surrounding each keyword, but you can easily do this in the while-loop.
To use this, simply pass a TextView and Pattern to addLinks() in onCreate() and Voila!
A working example for you:
public class Example extends Activity {
Pattern pattern = Pattern.compile("\\[[^]]*]");
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
popupDefinition("Example: A [pattern] or [model], as of something to be [imitated] or [avoided]");
}
// It seems like you can call "popupDefinition(dictionaryMap.get(term));" rather than pass both.
public void popupDefinition(String string){
SpannableString spannable = new SpannableString(string);
Matcher matcher = pattern.matcher(spannable);
// Create ActivitySpans for each match
while (matcher.find())
spannable.setSpan(new ActivitySpan(matcher.group()), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Create a new TextView with these spans and enable the clickable links
TextView textView = new TextView(this);
textView.setText(spannable);
textView.setMovementMethod(LinkMovementMethod.getInstance());
// Create and display an AlertDialog with this TextView
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setView(textView)
.create();
alertDialog.show();
}
public class ActivitySpan extends ClickableSpan {
String keyword;
public ActivitySpan(String keyword) {
super();
this.keyword = keyword;
}
#Override
public void onClick(View v) {
Context context = v.getContext();
Toast.makeText(context, keyword, Toast.LENGTH_SHORT).show();
}
}
}
I have a color picker which I use in sharedPrefereces. With the default colorpicker I managed to acheive what I want, but I noticed there is no black or white colors. http://www.yougli.net/android/a-photoshop-like-color-picker-for-your-android-application/
I would like to use this code but in the last rows, he shows an example, where I can see it is attached to a preferenced Screen. Instead of it I use my own activity with buttons where using shared Preferences I can save datas/values (so its not a preferenceActivity, just an Activity). For example clicking on a layout results:
OptVertexColor = (LinearLayout) findViewById(R.id.OptVC);
OptVertexColor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LoadChartVertexColor();
ColorPickerDialog dlg = new ColorPickerDialog(settings.this,
new ColorPickerDialog.OnColorChangedListener() {
public void colorChanged(int color) {
SaveChartVertexColor("vertexcolor", color);
}
}, loadedVertexColor);
dlg.setTitle("Select new color");
dlg.show();
}
});
The default color picker dialog appears and I can save a color. Now how can I use this without a preference screen and acheive the same thing? I tried to copy the code above to this code, but I coudnt figure out how to handle it.
public class MySettings extends PreferenceActivity implements OnPreferenceClickListener, ColorPickerDialog.OnColorChangedListener {
public boolean onPreferenceClick(Preference pref)
{
new ColorPickerDialog(this, this, DROIDS_COLOR_KEY, mPrefs.getInt(DROIDS_COLOR_KEY, DROIDS_COLOR_DEFAULT), DROIDS_COLOR_DEFAULT).show();
return true;
}
public void colorChanged(String key, int color)
{
((PreferenceScreen)this.findPreference(SETTINGS_KEY)).getEditor().putInt(key, color).commit();
}
}
Thank you in advance!
In your own Activity, add
implements ColorPickerDialog.OnColorChangedListener
to the class declaration.
Add to your class body:
public void colorChanged(String key, int color) {
//create your SharedPreferences and your SharedPreferences.Editor here
editor.putInt(key, color);
editor.commit();
}
And in a button click listener add:
new ColorPickerDialog(this, this, DROIDS_COLOR_KEY, mPrefs.getInt(DROIDS_COLOR_KEY, DROIDS_COLOR_DEFAULT), DROIDS_COLOR_DEFAULT).show();
This should work. Let me know if you I failed to answer your question, and I'll see what I can do.