I'm struggling with using EditText and Spannable text object, These days, I've read API documents around ten times, even I'm not certain that I understand correctly. So I'm looking for a kind of example which show me how to utilize EditText and Spannable.
Since you don't specify what you can't grasp from the API it's hard to answer your questions (short answer: rewrite your question to a specific questions rather than a general one).
A typical Spannable-example is something like this to turn selected text in an EditText into Italic:
Spannable str = mBodyText.getText();
if(mBodyText.getSelectionEnd() > mBodyText.getSelectionStart())
str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC),
mBodyText.getSelectionStart(), mBodyText.getSelectionEnd(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
else
str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC),
mBodyText.getSelectionEnd(),
mBodyText.getSelectionStart(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
This is cut and pasted from something else, so your direct-pastability might have suffered, but it at least shows a working example of a Spannable (in this case a StyleSpan). In the API you can find the other types of Spans (notably ImageSpan, which is a common questions among newly converted droiders).
I'm just starting to try to figure it out too, and it seems unnecessarily tricky.
Here's a working method to add NEW spannable text to an existing view. I wanted to add colored text to a view, and this seemed like the only way to do it.
Though it feels like an ugly hack, you can create a dummy TextView (not shown anywhere) and style the text there, then append that styled text to wherever you want. Credit for it goes to iifuzz at anddev.org. My code looks like so:
spanbuffer = new TextView(context);
spanbuffer.setText(newText, TextView.BufferType.SPANNABLE);
Spannable s = (Spannable) spanbuffer.getText();
s.setSpan(new ForegroundColorSpan(Color.RED), 0, newText.length() - 1, 0);
this.append(s);
I think you're supposed to be able to create new spannable text using the SpannableFactory, like so:
Spannable s = Spannable.Factory.getInstance().newSpannable(newText);
but I couldn't get this text to actually show new span effects, so I gave up.
Related
I do spell checking, and want to show all wrong letters in red.
Like the user typed Mossosoppo and the correct word would be Missisippi. I would want to show the wrong letters in red.
I tried with SpannedString, SpannableString and SpannableStringBuilder. I also checked all examples Google would find. Nothing worked ( = maximum 1 letter was shown in red or all letters after a position).
And i tried all possible combinations of flags -
SPAN_INCLUSIVE_INCLUSIVE, INCLUSIVE_EXCLUSIVE, EXCLUSIVE_INCLUSIVE, EXCLUSIVE_EXCLUSIVE.
This also didnt allow to use the same color in 2 places.
The maximum i could see was a combination of different properties like color, bold, italic.
The interface to set a Span is setSpan(Object _what_, int _start_, int _end_, int _flags_).
Now this doesnt tell if it is possible to call it several times for the same property (color). Did anybody succeed to add more than 1 color span to a single string ?
If so i could digg again, maybe i had an error when i tested all possible combinations of flags. At the moment i am switching code to a LinearLayout with many TextViews where each TextView contains a single character. That should work. But it isnt elegant.
Ok, thanks to Sajjad i found the solution.
It is possible to add 2 colors and more. However a ForegroundColorSpan may only be used once. So to set red 2 times you need 2 ForegroundColorSpan. If you reuse the same ForegroundColorSpan it does not work.
SpannableStringBuilder fullstring = new SpannableStringBuilder();
ForegroundColorSpan fg_red = new ForegroundColorSpan(Color.RED);
ForegroundColorSpan fg_black = new ForegroundColorSpan(Color.BLACK);
ForegroundColorSpan fg_red2 = new ForegroundColorSpan(Color.RED);
ForegroundColorSpan fg_black2 = new ForegroundColorSpan(Color.BLACK);
SpannableString blackText = new SpannableString("This is black");
blackText.setSpan(fg_black, 0, blackText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
fullstring.append (blackText);
SpannableString redText = new SpannableString("red");
redText.setSpan(fg_red, 0, redText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
fullstring.append(redText);
SpannableString blackText2 = new SpannableString("blackagain");
blackText2.setSpan(fg_black2, 0, blackText2.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
fullstring.append(blackText2);
SpannableString redText2 = new SpannableString("redagain");
redText2.setSpan(fg_red2, 0, redText2.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
fullstring.append(redText2);
return fullstring;
// the returned string can then be used for TextView.setText();
How can i set a particular string as a title in Edittext. I want to output to look like something like this:
Title
Some other text.
I have tried to make the text bold and give it a larger style. Something like this:
s.setSpan(new StyleSpan(Typeface.BOLD), 0, length ,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
s.setSpan(new RelativeSizeSpan(1.2f), 0, length , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
That does the trick but i wish if i could instead create a h1 tag around the string so the formatted html code i extract from Edittext can be displayed in textview or used elsewhere.
Update
It seems like a problem with Html class. Try something like this.
Log.d("Test", Html.toHtml(Html.fromHtml("<h1>Hello</h1>")));
You would get something like this in your logs:
<p dir="ltr"><b>Hello</b></p>
It seems like Html class is capable of converting h1 tags to spannable but not capable of being able to convert it back to h1 tags.
The fromHtml method converts the header tags to Spannable using a similar trick i already stated above. It's not implemented in the toHtml method and hence it don't create header tags from Spannable. Can someone try to fix this.
You can take a look at HTML.fromHtml(String text)
This will parse HTML and return a spanned string. The only thing notable is, that it's a bit tricky modifying the styles used for the spans.
Try something like this. Which worked for me
SpannableString text = new SpannableString(Html.fromHtml(<h1>Your content</h1>));
The image is from an app called kakao story.
Suppose there's a post with a list of comments like any sns apps.
When you click a comment, it inserts the user name of the commenter in the edit-text to indicate my new comment is a reply to the user.
(You can't add the same name more than once.)
When you hit backspace to delete the name, the entire characters that make up the name(e.g., chabeau in the example) will be deleted by 1-backspace.
I'm trying to mimic the behavior and want some pointers how to implement it or what to search for.
If you are in search of bubble view. You can achieve it by creating a subclass of android.text.style.DynamicDrawableSpan.ImageSpan which will convert a portion of EditText string into formatted span.
This SO Question will give you some basic idea about creating formatted span.
This is a good tutorial for customizing editext with spans.
And for deleting whole word at once, you can use SPAN_EXCLUSIVE_EXCLUSIVE property.
Below code will format the first four character of the string, Hope this will give you some hint.
final SpannableStringBuilder sb = new SpannableStringBuilder("your text here");
final ForegroundColorSpan fcs
= new ForegroundColorSpan(Color.rgb(158, 158, 158));
// Span to set text color to some RGB value
sb.setSpan(fcs, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
yourTextView.setText(sb);
EditText et = (EditText) findViewById(R.id.edit1);
et.setTextColor(Color.parseColor("yourColorCodeHere"));
I have a block of text coming from a webservice, and depending on some tags which I have predefined, I want to style the text before setting it to my TextView. For bold, italics, and underline, I was able to do this easily with the replaceAll command:
PageText = PageText.replaceAll("\\*([a-zA-Z0-9]+)\\*", "<b>$1</b>");
PageText = PageText.replaceAll("=([a-zA-Z0-9]+)=", "<i>$1</i>");
PageText = PageText.replaceAll("_([a-zA-Z0-9]+)_", "<u>$1</u>");
txtPage.setText(Html.fromHtml(PageText), TextView.BufferType.SPANNABLE);
So, to bold a word, surround it with *'s, for italics, surround with _.
But, for strikethrough, Html.fromHtml does not support the "strike" tag, so it can't be done this same way. I've seen examples of using Spannable to set the styling on one section of text, but it requires positional numbers. So, I guess I could loop through the text, searching for - (the tag to represent the strike), then searching for the next one, spanning the text in between, and repeating for all such strings. It will end up being 10 lines of looping code as opposed to 1 for the others, so I'm wondering if there is a more elegant solution out there.
If it is just TextView you can strike through using paint flags
TextView tv=(TextView) v.findViewById(android.R.id.text1);
tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
#Suresh solution works if you want to strikethrough the entire TextView but if you want to strikethrough only some portions of the text then use the code below.
tvMRP.setText(text, TextView.BufferType.SPANNABLE);
Spannable spannable = (Spannable) tvMRP.getText();
spannable.setSpan(new StrikethroughSpan(), 3, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Here text is the text which we want out TextView to display, 3 is the no. of characters (starting from 0) from where the strikethrough will start.
You can do it with a custom TagHandler such as the one on this SO question:
Spanned parsed = Html.fromHtml(PageText, null, new MyHtmlTagHandler());
And the TagHandler implements the methods:
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {
processStrike(opening, output);
}
}
....
Are you sure Html.fromHtml doesn't support <strike>? It's listed in this Commonsware blog post
It looks like is not really supported, at least it does not work on Android 3.1.
#RMS2 if text is small you can split it into two or three separate text views and apply flag only to the one which you want, not perfect for long texts ;(
Most of the applications we work in are going to use text somewhere throughout the project and thankfully, KTX provides some extension functions when it comes to these parts. For text, we essentially have some functions available for the SpannableStringBuilder class.
For example, after instantiating a Builder instance we can use the build methods to append some bold text:
textView.text =buildSpannedString {
strikeThrough {
append(
value ?: ""
)
}
}
I have this currently.
ClickableSpan span = new ClickableSpan(...){...};
String text = "I am some <b>awesome</b> text";
Spanned spanned = Html.fromHtml(text);
SpannableStringBuilder builder = new SpannableStringBuilder(spanned);
int start = builder.nextSpanTransition(0, builder.length(), StyleSpan.class);
int stop = builder.nextSpanTransition(start, builder.length(), StyleSpan.class);
builder.setSpan(span, start, stop, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(builder);
The TextView renders with the text that has the word "awesome" bolded and underlined (Yay). However in my view, I cannot focus the subregion of text I specified in the clickablespan. I can click on it with a touch event, but I cannot focus it. I am testing this on Android 1.5 + 2.1. I have also tried UrlSpan as well.
I have also tried instead of using a ClickableSpan, to actually attach an onClick listener to the entire block of text but that doesn't give the region focus, just makes clicking easier. Please help
Ok I just figured it out. I originally was looking at the UrlSpan documentation and then just blindly implemented ClickableSpan.
textView.setMovementMethod(LinkMovementMethod.getInstance());
And magically through the powers of this undocumented class ... it works. So basically what I think is going on, is the MovementMethod is a way to supply a textview with a strategy to handle cursor input.