I am trying to set span on a SpannableStringBuilder using flag SPAN_EXCLUSIVE_EXCLUSIVE and I am facing problem on further editing the text to which I am setting span.
Expected behaviour
1: Original text.
2: Text added before.
3: Text added after with space.
Unexpected Behaviour on adding text after styled text
I don't want the added text to be styled, and want to know what am I doing wrong.
EDIT 1:
The issue is happening on Moto X Play, but is not reproduced on Nexus 5X. Still testing on other devices.
You just probably add text not the way you should. Use .insert() and .append() methods of SpannableStringBuilder to add additional text.
I just tried what you try to achieve and here is the result:
TextView hratkyTextView = (TextView) findViewById(R.id.spannableHratkyTextView);
final StyleSpan bss = new StyleSpan(android.graphics.Typeface.BOLD); // Span to make text bold
// "Test text" part (in bold)
SpannableStringBuilder builder = new SpannableStringBuilder("Test text");
builder.setSpan(bss, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Prepending "before" (non-bold)
builder.insert(0, "before");
// Appending " after_with_space" to the end of the string
builder.append(" after_with_space");
hratkyTextView.setText(builder);
Result:
Nexus 7 Emulator running MainActivity with this code
TL;DR: Using some IMEs, like Gboard, when adding a char directly after a word (without space) the IME will replace the whole word tric with trick instead of just appending the c.
Detailed asnwer: How IMEs work with editors.
How some IMEs dictate commands to editors
IMEs communicate with editors (e.g. EditText) through InputConnection interface where they can send commands following user input, and get current text.
Gboard IME works in the following way:
gets text before and after cursor
detects the currently "composing" word and asks the editor to highlight and remember it (usually results in the word being underlined - check screenshot below)
Being aware of the currently composing word enables many features like suggesting words or auto-correcting spelling.
Whenever a char is inputted by the user, Gboard will ask the editor to set the currently composing text to a new value, i.e. replace trick by tricky
After a space is inputted, Gboard will do a final replace of currently composing region, eventually auto-correcting spelling
Currently composing region is reset to the next word.
This unfortunately breaks what we would normally expect from SPAN_EXCLUSIVE_EXCLUSIVE.
Related
Let's say I have an edittext field and I have to implement "backspace" functionality on it.
Deleting a simple letter character is fine, it works:
Character.isLetter(inputConnection.getTextBeforeCursor(1, 0).toString()) {
inputConnection.deleteSurroundingText(1, 0);
}
The problem comes when the character is an emoji symbol.
Its length is expressed as 2 utf-16 chars, for an example:
Grinning face: 😀
Unicode codepoint: U+1F600
Java escape: \ud83d\ude00
In such a case, I would simply remove 2 chars.
However, there are cases where an emoji is formed by multiple codepoints, like:
Rainbow flag: 🏳️🌈
Unicode codepoint sequence: U+1F3F3 U+FE0F U+200D U+1F308
Java escape: \ud83c\udff3\ufe0f\u200d\ud83c\udf08
When I press backspace, only one java escaped char gets deleted, not whole emoji. For flag example, only this \udf08 last part would be deleted, presenting user with screwed up emoji symbol. Surrogate pair check doesn't get me out of the hole here, I would still have screwed up emoji.
How can I properly find out the correct amount of chars to remove, so I would delete 1 whole emoji when pressing backspace? (for the flag example, I would need to get the number 6, to remove it fully)
Folks,
I need to capitalize first letter of every sentence. I followed the solution posted here
First letter capitalization for EditText
It works if I use the keyboard. However, if I use setText() to programatically add text to my EditText, first letter of sentences are not capitalized.
What am I missing? Is there a easy way to fix or do I need to write code to capitalize first letters in my string before setting it to EditText.
The only thing the inputType flag does is suggest to the input method (e.g. keyboard) what the user is attempting to enter. It has nothing to do with the internals of text editing in the EditText view itself, and input methods are not required to support this flag.
If you need to enforce sentence case, you'll need to write a method which does this for you, and run your text through this method before applying it.
You can use substring to make this
private String capSentences( final String text ) {
return text.substring( 0, 1 ).toUpperCase() + text.substring( 1 ).toLowerCase();
}
Setting inputType doesn't affect anything put into the field programmatically. Thankfully, programmatically capitalizing the first letter is pretty easy anyway.
public static String capFirstLetter(String input) {
return input.substring(0,1).toUpperCase() + input.substring(1,input.length());
}
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 an EditText called content. Inside it is some formatted text. I then want to switch between seeing the formatted text and the html by doing :
if(!showHtml)
content.setText(Html.fromHtml(content.getText().toString()), BufferType.SPANNABLE);
else
content.setText(Html.toHtml(content.getText()));
If the formatted text is "test test", the html comes out as <p>test <b>test </b></p> which is fine, but when going back, the formatting is lost and I get "test test".
If the formatted text is "test test", the html comes out as <p><b>test</b> test</p>, which is correct once again. However, the text obtained when going back is "test test".
So what it looks like is that the formatting of the first word is applied to the rest of the text (I've tested it on longer strings).
Has anyone encountered this before, and how could I go about solving this?
Edit 1 It seems that with EditText.setText(), it automatically uses the Editable flag and completely ignores my request for a Spannable. Could this be where the problem is coming from?
I was being a fool. I had completely forgotten that I had a TextWatcher that modified the styles that were applied. All I needed to do was set a flag telling it not to modify the styles if it was after converting from html.
Im creating an app that has a number of buttons, and when these buttons are clicked I want the value to be added to a text box/label (That can then be sent as a text) - Basically instead of typing a text you click the pre-written words as a button to put them into a text.
However In the blocks editor I can only set the value of the button, to the text box. So It only contains one value, and if another is clicked it simply replaces it.
How do I go about inserting a value into a text box/label using the blocks editor?
Thanks.
[EDIT] I've figured out a way to do it if anyone else had similar problems, you use the blocks:
when button click > set MYtextbox.text to > (Join block from text menu) > MYtextbox.text (Join) MYbutton.text
-Please changed this to solved.
I'm not familiar with blocks editor, but in java I would write the following, maybe it will help you:
yourTextView.setText(yourTextView.getText() + " " + newText);
It is easy. There is the "join" block in the basic text blocks drawer.
When you are adding text to a text box that already has text, for example Textbox1 then you should assemble the blocks as Textbox1 join Label1. It is very similar to what we say in visual basic, for example Textbox1 = Textbox1 & Label1 or whatever.
You can also use maketext block. When you use this block set Textbox1 to maketext block. First insert Textbox1 block in the first socket and add new text with basic text block to the ensuing sockets.