I want to restore previous text content on pressing undo button. With code below I can see what how did String changed, save new string to stack. For restore I just pop stack to get previous text. However that approach does not consider any changes in spannable. How to track what was changed be it either text or its styling or both?
Stack<String> save = new Stack<>();
Runnable saveRunnable = new Runnable() {
#Override public void run() {
if (tvValueDesc != null) {
String text = tvValueDesc.getText().toString();
if (save.isEmpty()) save.push(text);
if (!save.peek().equals(text)) save.push(text);
handler.postDelayed(this, 1000);
}
}
};
#OnClick(R.id.btn_undo) void restore() {
handler.removeCallbacksAndMessages(null);
if (!save.empty()) save.pop();
if (!save.empty()) {
tvValueDesc.setText(save.peek());
} else {
tvValueDesc.setText(null);
}
handler.postDelayed(saveRunnable, 1000);
}
For this you need to create Custom textPojo that includes all text propertices which you want to store ,like typeFace, text,Text Style, text size, text color , Text Alignment etc,
And When you store text while pressing button store all this information into TextPojo and maintain TextPojo stack rather maintaining single String .
To save text with spannable we should take charsequence from spannable, not the string
Related
I have made a class that is responsible for monitoring an EditText widget following the Observer pattern. Its sole function is to disable or re-enable auto-correct based on a method call. I am able to successfully achieve this, but the problem is that the new InputType only applies to new text I add to the EditText - old text still retains the red underline to show that it can be auto-corrected.
Is there any way I can force the new InputType to apply to the entire EditText block, and not simply the new content I add? I tried calling editText.invalidate() and editText.refreshDrawableState() in the hope all the text would refresh, but to no avail.
final class SpellCheckerObserver implements EditTextObserver {
public static final int KEY = KeyGenerator.generateUniqueId();
private int defaultInputType;
SpellCheckerObserver(EditTextSubject subject) {
subject.attach(SpellCheckerObserver.KEY, this);
}
#Override
public void activating(EditText editText) {
defaultInputType = editText.getInputType();
editText.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
#Override
public void deactivating(EditText editText) {
editText.setInputType(defaultInputType);
}
}
I found out the answer whilst looking through the source code for TextView, where I came across the removeSuggestionSpans() method.I wasn't aware that the suggestions were in fact a type of span, (unsurprisingly, the SuggestionSpan)
This meant I was able to remove the red underline with the following code:
SuggestionSpan[] spans = editText.getText().getSpans(
0, editText.length(), SuggestionSpan.class
);
if (spans.length > 0) {
for (SuggestionSpan span : spans) {
editText.getText().removeSpan(span);
}
}
I add a text like this:
tv.setText("This is text created with StringBuilder");
Then I track which word a user longclicks on, and want to highlight that word for some short period of time:
tv.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
int offset = tv.getOffsetForPosition(coordinates.get(0), coordinates.get(1));
int[] offsets = getWordOffsets(text.toString(), offset);
int startOffset = offsets[0];
int endOffset = offsets[1];
// here I want to highlight the word starting from startOffset to endOffset
I've read that I should use SpannableString, however most examples show that I should created new SpannableString using the entire text, and then I can add styles to part of it. Is there any way to make part of the text in TextView spannable? Or should I create new SpannableString strings from TextView content and set spans every time the long click event is triggered?
you can use some countdown timer
//___ HIGHLIGHT HERE ______
new CountDownTimer(500,500){
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
//___ UN HIGHLIGHT HERE ______
}
}.start();
and for the highlight you can use something like
textView.setText(Html.fromHtml("<font color='#FF0000'>text</font>"));
I got a textfield that the user can write text in, and the text is saved into preferences so that the text remains the same as they left it. But I´ve must´ve done something wrong because when it flushes the preferences and you re-enter that screen again the text have been duplicated and placed up on eachother, and some part of the stored text isn´t removeable.
This is how I´ve done:
public final String fieldString = "";
public final String areaString = "";
//
final TextField textField = new TextField(prefs.getString(fieldString),textstyle);
textField.setX(250);
textField.setY(800);
textField.setMaxLength(23);
textField.setWidth(textWidth);
textField.setHeight(textHeight);
stageText.addActor(textField);
I flush the prefs as the user clicks the backbutton to the mainscreen.
btnArrow.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
game.setScreen(0);
//Saves the entered text.
prefs.putString(fieldString, textField.getText());
prefs.putString(areaString, textArea.getText());
prefs.flush();
}
});
Without seeing the navigation code, from your description it sounds like multiple text fields are getting added on top of each other each time you return to the screen.
I have a TextView to display a paragraph of text and I want my application to speak individual words when they are pressed, using TTS. It would look better if words can be highlighted when pressed. I have implemented it using a ClickableSpan for each word. It works almost fine except that I do not see how to reset the highlighted state back to normal once playback is done. Each time I click a new word the previous word loses the highlight and the new one gets highlighted, but I do not know how to remove the highlight once TTS calls back:
My TextView:
<TextView
android:id="#+id/sentence"
...
android:textColorHighlight="#color/i_blue"
/>
To fill in the TextView, I use:
SpannableStringBuilder strBuilder = new SpannableStringBuilder();
Iterator<Word> iterator = e.getWordList().iterator();
int wordStart, wordEnd;
while (iterator.hasNext()) {
Word w = iterator.next();
wordStart = strBuilder.length() + w.getPrefix().length();
wordEnd = wordStart + w.getWord().length();
strBuilder.append(w.getPrefix() + w.getWord() + w.getSuffix());
final String currentWord = w.getWord();
ClickableSpan readWord = new ClickableSpan() {
private String clickedWord = currentWord;
public void onClick(View view) {
Message msg = m_HandlerReadWord.obtainMessage();
msg.obj = clickedWord;
m_HandlerReadWord.sendMessage(msg);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
strBuilder.setSpan(readWord, wordStart, wordEnd, 0);
}
m_SentenceView.setText(strBuilder);
m_SentenceView.setMovementMethod(LinkMovementMethod.getInstance());
And I also have this method which is called once TTS calls back when it is done playing the word:
public void resetHighlight() {
//What can I do there to reset any highlighted word?
}
Is there a way I can do it? Or is there a better approach than ClickableSpan?
I finally found a trick that works for me. When the text color in the TextView changes, all highlights are reset. So if I trigger a text color change in the callback of the TTS, then the highlight gets removed. The dirty part is that the triggered color change must be a different color. So I have to change the colors both when TTS calls back and in the onClick handler of the ClickableSpan. And I set these two colors to two almost identical colors.
My ClickableSpan:
final int AlmostBlack = m_Resources.getColor(R.color.i_black_almost);
ClickableSpan readWord = new ClickableSpan() {
private int almostBlack = AlmostBlack;
public void onClick(View view) {
TextView v = (TextView) view;
v.setTextColor(almostBlack);
...
And in the handler when TTS calls back:
m_SentenceView.setTextColor(m_Resources.getColor(R.color.i_black));
If you want to do something similar but without waiting for TTS or anything to call back, you can use a Color State List to trigger color changes when the view is pressed or released:
The Color State List, res/color/clickable_words.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:color="#color/i_black_almost" android:state_pressed="true"/>
<item android:color="#color/i_black" />
</selector>
The TextView:
<TextView
android:id="#+id/sentence"
...
android:textColor="#color/clickable_words"
android:textColorLink="#color/clickable_words"
android:textColorHighlight="#color/i_blue" />
I have an application where I need to display a list of numbers, but the numbers need to be formatted based on their value. Negative numbers are shown in normal text, positive numbers shown as bold. Also, the number needs to always appear positive in the text view. I tried extending TextView with setText overriden as such:
#Override
public void setText(CharSequence text, TextView.BufferType type) {
double number = Double.parseDouble(text.toString());
if (number > 0) {
this.setTypeface(this.getTypeface(), BOLD);
} else {
this.setTypeface(this.getTypeface(), NORMAL);
number = Math.abs(number);
}
super.setText(number + "", type);
}
This didn't quite work, as the setText was being called multiple times on the same MyTextView. This resulted in every number appearing bold, as it was positive the next time through.
I would like to keep this logic in a widget, as opposed to where the text is being set, as this is a very common occurrence in my application.
Is there a way that I can do this in a widget?
Just add a member variable to your class to check whether it was already modified or to keep the original value.
private double originalValue = 0;
#Override
public void setText(CharSequence text, TextView.BufferType type) {
if(originalValue==0) {
originalValue = Double.parseDouble(text.toString());
}
this.setTypeface(this.getTypeface(), originalValue>0 ? BOLD : NORMAL);
super.setText(Math.abs(originalValue), type);
}
Ok, I ended up just making an adapter for each list that used this special case, and took care of it in the activity for any other instance of it. Something like this:
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView text = (TextView) view.findViewById(R.id.special_text);
double amount = cursor.getDouble(cursor.getColumnIndex(DbAdapter.KEY_NUMBER));
if (amount > 0) {
amountText.setTypeface(null, Typeface.BOLD);
} else {
amountText.setTypeface(null, Typeface.NORMAL);
amount = Math.abs(amount);
}
text.setText(amount);
}