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>"));
Related
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
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 a simple CountDownTimer that displays its content in a textView. I am trying to accomplish the following:
during count down, the view is not clickable: textview.setClickable(false);
after count down finish, if the user clicks the textview, the count down should restart.
So I try a combination of
#Override
public void onFinish() {//inside CountDownTimer
view.setClickable(true);
}
and
textview.setOnClickListener(countAgain);
OnClickListener countAgain = new OnClickListener() {//inside activity
#Override
public void onClick(View v) {
// counter.cancel();
counter.start();
}
};
But this is not doing it. Any ideas?
Set onclick listener for that text view, make it clickable .
In onclicklistner, make textview as non-clickable( yourTextView.setclickable(false) ).
change the text view values as you want and every time check the value against 0. When it becomes zero, make the text view clickable( yourTextView.setclickable(true) ).
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);
}