create spaces between image and string in spannable setSpan - android

I need to place an image and string in the center of the button. Need to create spaces between them.
a Hello (%1$d)
My code:
String textValue = getResources().getString(R.string.hello_text);
final Spannable buttonLabel = new SpannableString(String.format(textValue, 2));
//buttonLabel.setSpan(new ImageSpan(getApplicationContext(), R.drawable.hello_imagel,
// ImageSpan.ALIGN_BOTTOM), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mButton.setText(buttonLabel);
I need give spaces between the image and the text. I tried giving spaces in the strings.xml but it doesn't display the spaces. After adding the below xml, the image is to the left and the string is in the center. I want the image and string to be in center with few spaces between image and string
xml:
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#2A2A2A"
android:drawableLeft="#drawable/hello_image1"
android:gravity="center"

If you don't need to show an icon inside a string you can add drawable to your button.
i.e. an icon at the left side of the text:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="#drawable/icon"
android:drawablePadding="20dp">
where #drawable/icon is your icon and 20dp is padding between icon and text
Shure you can do the same from code - take a look at setCompoundDrawables and setCompoundDrawablePadding

sorry to be late, I hope this method helps you, is on kotlin:
fun setLeftIcon(roundButton: RoundButton, iconId: Int) = with(roundButton) {
if (iconId == DEFAULT_IMAGE_ID) return
val currentText = text.toString()
// The spaces are a workaround to add some space between the image and the text
val buttonLabel = SpannableString(" $currentText")
buttonLabel.setSpan(
ImageSpan(context, iconId),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
text = buttonLabel
}

Related

How to have drawable wrap with a TextView? (Android)

I often need to have some piece of dynamic text in a TextView, with some drawable image at the end of it.
I'm having troubles making it look nice when the text needs to span onto 2 lines. I would want the image to go inline with the text.
This is what it looks like:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="This is my favourite which has a really long piece of string which will wrap"
app:drawableEndCompat="#drawable/ic_baseline_favorite_border_24" />
This is what I want it to look like:
Drawable End in a TextView, or putting an ImageView next to a TextView doesn't work. Is there an easy way to get this image inline with the text as if it is part of the text?
Based on the Answer here, thanks to #Linh. And on the VerticalImageSpan
This is manipulated to add a drawable at the end of the text:
TextView extension function:
fun TextView.addImageAtEnd(#DrawableRes imgSrc: Int, imgWidth: Int, imgHeight: Int) {
val ssb = SpannableStringBuilder(this.text)
val drawable = ContextCompat.getDrawable(this.context, imgSrc) ?: return
drawable.mutate()
drawable.setBounds(
0, 0,
imgWidth,
imgHeight
)
ssb.setSpan(
VerticalImageSpan(drawable),
length() - 1,
length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
this.setText(ssb, TextView.BufferType.SPANNABLE)
}
Usage:
textView2.text = "This is my favourite which has a really long piece of string which will wrap "
textView2.addImageAtEnd(
R.drawable.heart_outline,
resources.getDimensionPixelOffset(R.dimen.dp_30),
resources.getDimensionPixelOffset(R.dimen.dp_30)
)
Result:

Change position of icon drawable in TextView

In my case, I have a textView with a drawable icon at the start of it(android:drawableStart), when the text of textView is multi-line, the icon goes in the vertical center of textView, but I want the icon to be aligned to the top of the text, how can I do this?
I don't want use any other layouts for doing this
There is api to set the drawable, but first you should set the bounds .
You can use setCompoundDrawablesWithIntrinsicBounds to set the drawable icons.
textview.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getApplicationContext(), R.drawable.icon), null, ContextCompat.getDrawable(getApplicationContext(), R.drawable.icon_two), null);
As according to the interface you can see the position clearly and use accordingly to your need.
public void setCompoundDrawablesWithIntrinsicBounds (int left,
int top,
int right,
int bottom)
It is something different but a quick workaround.
Just use a Checkbox instead of a TextView and use android:button to define your drawable:
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="#drawable/..."
android:gravity="top"
android:clickable="false"
android:text=".."/>
The approach I followed is to use SpannableString by setting a Span to the beginning of the string, being the Spain an ImageSpain
fun TextView.setDrawableAtStart(context: Context, textToSet: String?, #DrawableRes drawableRes: Int) {
if (textToSet.isNullOrBlank()) return
text = SpannableString(" $textToSet ").apply {
val drawable = ContextCompat.getDrawable(context, drawableRes) ?: return
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
setSpan(
ImageSpan(drawable, ImageSpan.ALIGN_BASELINE),
0, // Start position
1, // End position
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
}
}
I encourage you to read this interesting article about styling a text in Android.

Add drawable starting of multiline text view

Need to add Quote as a drawable in multiline text like below mentioned screen. Like you can see quote is in a starting of multiline text and next line text is just starting from the below to the quote.
I need to use TextView to achieve this and quote should be a drawable.
If I am using drawableLeft property of TextView Its showing like below mentioned image.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!\nHello World!\nHello World!\nHello World!"
android:drawableStart="#drawable/ic_quote"
android:drawableLeft="#drawable/ic_quote"/>
You can create a SpannableString to add the drawable :
TextView myTextView = (TextView) findViewById(R.id.myTextView);
ImageSpan imageSpan = new ImageSpan(this, R.drawable.ic_quote);
SpannableString spannableString = new SpannableString("*" + myTextView.getText()); // "*" will be replaced by your drawable
int start = 0; // the start index, inclusive
int end = 1; // the end index, exclusive
int flag = 0;
spannableString.setSpan(imageSpan, start, end, flag);
myTextView.setText(spannableString);
And in your layout :
<TextView
android:id="#+id/myTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!\nHello World!\nHello World!\nHello World!"/>
Try using android:gravity="top"
if it didnt work then go with negative margin like this
android:drawablePadding="-20sp"
Another alternative way is to take an ImageView beside TextView inside LinearLayout so you can apply gravity
You can use SpannableStringBuilder.
val spannableText = SpannableStringBuilder("*Your text!").apply {
val imageSpan = ImageSpan(context, R.drawable.your_icon)
setSpan(imageSpan, 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
}
textView.setText(spannableText, TextView.BufferType.SPANNABLE)
The symbol * will be raplaced witn your icon.

PagerTabStrip is clipping off the icon

The design called for just icon on the tab of the PagerTabStrip.
Here's the XML:
<android.support.v4.view.PagerTabStrip
android:id="#+id/tbstrp_album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foregroundGravity="bottom"
android:padding="0dp"
android:background="#color/offWhite">
Here's my getPageTitle inside the adapter:
#Override
public CharSequence getPageTitle(int position) {
// This is "generic" string that we will use as the title to be replaced.
String title = "title";
Drawable myDrawable = oContext.getDrawable(R.drawable.alpha);
// initiate the SpannableString builder
SpannableStringBuilder spanBuilder = new SpannableStringBuilder(title); // space added before text for convenience
// set the drawable's size...if it could be too big or too small for display
myDrawable.setBounds(0, 0, 50, 50);
// turn the Drawable into ImageSpan and align it along the baseline
ImageSpan imageSpan = new ImageSpan(myDrawable, ImageSpan.ALIGN_BASELINE);
// CRUCIAL: this is where we replace the "title" w/ the image
// 0: we start from the beginning
// title.length(): we are replacing the entire string
// the last flag doesn't do anything in our case
spanBuilder.setSpan(imageSpan, 0, title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spanBuilder;
}
The output looks like this:
What's causing the strip clipping the image? Thanks!
It turns out this statement is the culprit:
myDrawable.setBounds(0, 0, 50, 50);
I changed the second argument which is the "top" to 30 and the icon was not clipped.
The unanswered question is still...why do I have to specify a value for the "top" argument.

Android Multi Column Text

Is there any way in which I can display a long text on multiple columns?
For example I need to display an article, I have the entire String and I want to place it on 3 columns. How can I achieve this? Are there any libraries that can help me or do you know how should I approach this problem?
Any suggestion is appreciated. Thanks.
EDIT: The issue is the splitting of the string not the layout. I know I can use TableLayout... or weights... to distribute column evenly and so on. The problem is how do I split the String properly. Maybe 2 column would get filled and the 3rd just half of it? I don't know how to approach this, not the actual layout.
Check the TableLayout. To split your text you could split your text after 1/3 of your count of chars. Of cource you have to split the text at one whitespace charecter. UPDATE: See also my example code at the end of my posting.
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<TextView
android:text="#string/table_layout_4_open"
android:padding="3dip" />
<TextView
android:text="#string/table_layout_4_open_shortcut"
android:gravity="right"
android:padding="3dip" />
</TableRow>
<TableRow>
<TextView
android:text="#string/table_layout_4_save"
android:padding="3dip" />
<TextView
android:text="#string/table_layout_4_save_shortcut"
android:gravity="right"
android:padding="3dip" />
</TableRow>
</TableLayout>
For splitting you can test this code. The algorithem could maybe a little better be nearer to the split boundaries, but it works.
public static String[] getRows(String text, int rows) {
// some checks
if(text==null)
throw new NullPointerException("text was null!");
if(rows<0 && rows > 10)
throw new IllegalArgumentException("rows must be between 1 and 10!");
if(rows==1)
return new String[] { text };
// some init stuff
int len=text.length();
int splitOffset=0;
String[] ret=new String[rows];
Pattern whitespace = Pattern.compile("\\w+");
// do the work
for(int row=1;row<rows;row++) {
int end;
int searchOffset=len/rows*row;
// search next white space
Matcher matcher = whitespace.matcher(text.substring(searchOffset));
if(matcher.find() && !matcher.hitEnd()) {
// splitting on white space
end=matcher.end()+searchOffset;
} else {
// hard splitting if there are no white spaces
end=searchOffset;
}
ret[row-1]=text.substring(splitOffset, end);
splitOffset=end;
}
// put the remaing into the last element
ret[rows-1]=text.substring(splitOffset);
return ret;
}
Are you looking for a 'newspaper column' style? Once the first (fixed size) text-box fills, the text should continue into the other and so on?
If so, why not display your long string into a WebView where you can more easily achieve this using HTML and CSS?
use (Calculate text size according to width of text area)
Paint paint = new Paint();
Rect bounds = new Rect();
int text_height = 0;
int text_width = 0;
paint.setTypeface(Typeface.DEFAULT);// your preference here
paint.setTextSize(25);// have this the same as your text size
String text = "Some random text";
paint.getTextBounds(text, 0, text.length(), bounds);
text_height = bounds.height();
text_width = bounds.width();
to calculate how much is your text going to take space.
and calculate view.getWidth() about how much is your view width...
Then do the needful by dividing the text accordingly.

Categories

Resources