ImageSpan in a widget? - android

Are there any limitations to adding an ImageSpan to a widget?
This identical code works fine in a standard TextView.
SpannableStringBuilder buf = new SpannableStringBuilder("");
if(!TextUtils.isEmpty(message.getMessageBody())) {
SmileyParser parser = SmileyParser.getInstance();
buf.append(parser.addSmileySpans(group ? message.getMessageBodyWithoutName() : message.getMessageBody()));
}
view.setTextViewText(R.id.message_body, buf);
Thanks.
Edit 1:
public CharSequence addSmileySpans(CharSequence text) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
Matcher matcher = mPattern.matcher(text);
while (matcher.find()) {
int resId = mSmileyToRes.get(matcher.group());
builder.setSpan(new ImageSpan(mContext, resId),
matcher.start(), matcher.end(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return builder;
}

The smiley's are local assets.
I am going to interpret this literally, that you mean your images are in assets/.
My guess is that the home screen is having difficulty resolving your asset reference. As a test, try putting the images on external storage and using Uri.fromFile() to create your Uri. If that works, try putting them as drawable resources and using the resource IDs. Or, try the resource Uri syntax:
Uri.parse("android.resource://your.package.name.goes.here/" + R.raw.myvideo);

Related

How to write an Index?

I´m writing a calculator for chemistry in Android Studio and I have no idea about how to write the index of the elements in the given form:
H2O
With the index in the bottom left.
How can I achieve this?
private static CharSequence makeStringLikeFormula(String str) {
if (str == null) return "";
final SpannableString spannable = new SpannableString(str);
final Matcher matcher = Pattern.compile("\\d+").matcher(str);
while (matcher.find()) {
spannable.setSpan(new SubscriptSpan(), matcher.start(), matcher.end(), 0);
}
return spannable;
}
example
textView.setText(makeStringLikeFormula("H2O22"));
You will have to use SubscriptSpan. From official android documentation :
https://developer.android.com/reference/android/text/style/SubscriptSpan
You might also want to take a look on this answer Subscript and Superscript a String in Android
Basically, since you need both subscript and superscript, a way to do this is through HTML, and you can add HTML on android.
TextView allows you to insert HTML.
The simplest way is to use html- Do like this:-
((TextView)findViewById(R.id.text)).setText(Html.fromHtml("H<sub>2</sub>O"));

How to Bold (Span) the searched text in string dynamically?

I have a string, in which i have to find a word being searched from end user and make it bold to highlight.
Example:
String : Address must have a format. Address can be of multiple line.
Required Text: Address must have a format. Address can be of multiple line.
After going through different Approaches. I have written the following method which will span the searched Text in string.
If you want to span the same text multiple time they can use this method as well.
public CharSequence highlightTextString(String completeText, String searchText) {
String temp = completeText.toLowerCase();
SpannableStringBuilder highlightText = new SpannableStringBuilder(completeText);
Pattern pattern = Pattern.compile(searchText.toLowerCase());
Matcher matcher = pattern.matcher(temp);
while (matcher.find()) {
StyleSpan styleSpan = new StyleSpan(android.graphics.Typeface.BOLD);
highlightText.setSpan(styleSpan, matcher.start(), matcher.end(), 0);
}
return highlightText;
}

Parsing ImageGetter image as text

Using ImageGetter and HTML, I have some emoticons in an edittext (code below), however I want to be able to recognize these images later in the edittext so it can be stored as a string. Does anyone know how to retrieve this, or should I keep a string updated with string value instead.
Thanks
ImageGetter imggtr = new ImageGetter()
{
public Drawable getDrawable(String source)
{
Drawable d = getActivity().getResources().getDrawable(getEmoticonDrawable(position));
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
return d;
}
};
Spanned cs = Html.fromHtml("<img src='" + getActivity().getResources().getDrawable(getEmoticonDrawable(position))
+ "'/>", imggtr, null);
mEditor.append(cs);
As you mentioned, you should keep a separate string in memory. If you try to parse the html back to a string, it's going to be complicated and not very flexible.

Highlight multiple words in a string using SpannableString

I'm using a SpannableString to underline certain words, however, I realized the code I have only highlights the first word if there are multiple words. Not exactly sure how to accomplish highlighting multiple words:
String keyword = "test";
String text = "This is a test to underline the three test words in this test";
SpannableString output = new SpannableString(text);
if (text.indexOf(keyword) > -1)
{
int keywordIndex = text.indexOf(keyword);
int keywordLength = keyword.length();
int start = keywordIndex;
int end = keywordIndex + (keywordLength);
output.setSpan(new UnderlineSpan(), start, end, 0);
}
I was thinking I could split the text at every space and loop through it, but wasn't sure if there was a better way.
I do have this code to highlight multiple words using a regular expression, however, I'm try to avoid regular expressions since it's in an Android app and I'm using it in a ListView and I'm told they are very expensive. Also this code I have only highlight whole words, so using the example text above, if the word "protest" was in the sentence, it wouldn't get highlighted using this code:
Matcher matcher = Pattern.compile("\\b(?:test")\\b").matcher(text);
while (matcher.find())
{
output.setSpan(new UnderlineSpan(), matcher.start(), matcher.end(), 0);
}

SpannableStringBuilder to create String with multiple fonts/text sizes etc Example?

I need to create a String placed in a TextView that will display a string like this:
First Part Not Bold BOLD rest not bold
So I want to know how I could use SpannableStringBuilder to do this?
I could use three TextEdit to accomplish this but I would like to use best solution.
First Part Not Bold BOLD rest not bold
You can do this either as #Rajesh suggested or by this.
String normalBefore= "First Part Not Bold ";
String normalBOLD= "BOLD ";
String normalAfter= "rest not bold";
String finalString= normalBefore+normalBOLD+normalAfter;
Spannable sb = new SpannableString( finalString );
sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), finalString.indexOf(normalBOLD)+ normalBOLD.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //bold
sb.setSpan(new AbsoluteSizeSpan(intSize), finalString.indexOf(normalBOLD)+ normalBOLD.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//resize size
to show this in TextView
textview.setText(sb, TextView.BufferType.SPANNABLE);
The accepted answer is fine (and I upvoted it), but it fails to use the SpannableStringBuilder as the submitter requested. As I had a case where the Builder made the most sense, here is the code for that (with a bonus use of also changing the color of the text if that is helpful to others). Note that you could also provide the initial string to the SpannableStringBuilder constructor, but I set it here to use "append" to be clear that you can append a lot before your desired "bold" text and then just record the start as shown. I would suspect that this is also faster code than the accepted answer.
SpannableStringBuilder longDescription = new SpannableStringBuilder();
longDescription.append("First Part Not Bold ");
int start = longDescription.length();
longDescription.append("BOLD");
longDescription.setSpan(new ForegroundColorSpan(0xFFCC5500), start, longDescription.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
longDescription.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, longDescription.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
longDescription.append(" rest not bold");
If you are using Kotlin you can do the following using the android-ktx library
val s = SpannableStringBuilder()
.append("First Part Not Bold ")
.bold { append("BOLD") }
.append("Rest not bold")
The bold is an extension function on SpannableStringBuilder. You can see the documentation here for a list of operations you can use.
Another example:
val s = SpannableStringBuilder()
.color(green, { append("Green text ") })
.append("Normal text ")
.scale(0.5, { append("Text at half size " })
.backgroundColor(green, { append("Background green") })
Where green is a resolved RGB color.
It is even possible to nest spans so you end up with an embedded DSL:
bold { underline { italic { append("Bold and underlined") } } }
You will need the following in your app module level build.gradle for it to work:
repositories {
google()
}
dependencies {
implementation "androidx.core:core-ktx:1.2.0"
}
From API 21 SpannableStringBuilder includes a simple method to do this. Here is a solution example:
SpannableStringBuilder builder= new SpannableStringBuilder();
StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
builder.append("First Part Not Bold ")
.append("BOLD ", boldSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
.append("rest not bold");
Kotlin version:
val builder = SpannableStringBuilder()
val boldSpan = StyleSpan(Typeface.BOLD)
builder.append("First Part Not Bold ")
.append("BOLD ", boldSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
.append("rest not bold")
Use HTML code in TextView using the Html class:
Spanned styledText = Html.fromHtml("First Part Not Bold <b>BOLD</b> rest not bold");
textView.setText(styledText);
This code should set to bold everything that comes inside the html bold tag. And it also deletes the tag so only the content inside is displayed.
SpannableStringBuilder sb = new SpannableStringBuilder("this is <b>bold</b> and this is <b>bold too</b> and this is <b>bold too, again</b>.");
Pattern p = Pattern.compile("<b>.*?</b>", Pattern.CASE_INSENSITIVE);
boolean stop = false;
while (!stop)
{
Matcher m = p.matcher(sb.toString());
if (m.find()) {
sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.delete(m.end()-4, m.end());
sb.delete(m.start(), m.start() + 3);
}
else
stop = true;
}
This code can also be adapted for other html style tags, such as Superscript (sup tag), etc.
SpannableStringBuilder sb = new SpannableStringBuilder("text has <sup>superscript</sup> tag");
Pattern p = Pattern.compile("<sup>.*?</sup>", Pattern.CASE_INSENSITIVE);
boolean stop = false;
while (!stop)
{
Matcher m = p.matcher(sb.toString());
if (m.find()) {
sb.setSpan(new SuperscriptSpan(), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.delete(m.end()-6, m.end());
sb.delete(m.start(), m.start() + 5);
}
else
stop = true;
}
To set the color, just use the ForegroundColorSpan with setSpan.
sb.setSpan(new ForegroundColorSpan(Color.rgb(255, 0, 0)), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
Hope it helps.
We can also use SpannableStringBuilder with TextAppearanceSpan to accomplish that. Follow the below steps to implement like that.
Create a style in styles.xml.
<style name="BoldStyle">
<!-- Can add other styling attributes -->
<item name="android:textStyle">bold</item>
......
</style>
Use the below code.
SpannableStringBuilder builder = new SpannableStringBuilder("First Part Not Bold BOLD rest not bold");
builder.setSpan(new TextAppearanceSpan(this, R.style.BoldStyle), 20, 24, 0);
((TextView)findViewById(R.id.tv7)).setText(builder);
That's it. Hope it'll help someone.
you can bold and resize a part of your string in kotlin
val s = SpannableStringBuilder()
.append("First Part Not Bold And No Resize ")
.bold { scale(1.5f, { append("Second Part By Bold And Resize " )}) }
.append("Third Part Not Bold And No Resize")
yourTextview.text = s
So I know this has been solved, and even as requested with SpannableStringBuilder but in the event you wanted to build a string more dynamically I figured I would put this up.
// Stuff needed
TextView DataTextView = (TextView)rootView.findViewById(R.id.DataView);
String Fields[] = {...database column names as strings... "x","y"};
String DataString = new String();
int start,stop; // Start and Stop of formatting
// Final Result
SpannableStringBuilder coloredString = new SpannableStringBuilder();
SpannableString temp; // Small segment of colored string
for (int i =0; i < Fields.length; i++)
{
if (database_result.containsKey(Fields[i])) // Be sure a field exists in the ContentValues
{
DataString = Fields[i]+": ";
start = DataString.length();
DataString = DataString+ +database_result.getAsInteger(Fields[i])+" ";
stop= DataString.length();
temp = new SpannableString(DataString);
temp.setSpan(new ForegroundColorSpan(Color.WHITE),start, stop, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
coloredString.append(temp);
}
}
DataTextView.setText(coloredString);
database_result is a ContentValues type that I constructed from the returned Cursor type of the SQL query. The only problem I had with this was at first it was only ColorSpaning the first segment. It seams that you need to declare a new ForegroundColorSpan every time you want to use one (or any other kind of span) in a loop.
Why would you use SpannableStringBuilder when you can use SpannableBuilder?? (https://gist.github.com/qtyq/90f9b4894069a8b3676c)
SpannableString ss = SpannableBuilder.init("First Part Not Bold BOLD rest not bold")
.makeBold("BOLD")
.create()
For Xamarin.Android:
SpannableStringBuilder TextoFormateado = new SpannableStringBuilder();
TextoFormateado.Append("Not Bold");
int start = TextoFormateado.Length();
TextoFormateado.Append("Bold and Red");
TextoFormateado.SetSpan(new ForegroundColorSpan(new Color(255, 0, 0, 149)),
start, TextoFormateado.Length(), SpanTypes.ExclusiveExclusive);
TextoFormateado.SetSpan(new StyleSpan(TypefaceStyle.Bold),
start, TextoFormateado.Length(), SpanTypes.ExclusiveExclusive);
TextoFormateado.Append("Not bold");
TxtFinalText.TextFormatted = TextoFormateado;

Categories

Resources