SpannableString with Image example
Found the following and it seems to do the job:
public class TestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView = (TextView) findViewById(R.id.textview);
SpannableString ss = new SpannableString("abc");
Drawable d = ContextCompat.getDrawable(this, R.drawable.icon32);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(ss);
}
Android - ImageSpan - How to center align the image at the end of the text
You can try my CenteredImageSpan
.
You can customize in draw
method by calculating transY -= (paint.getFontMetricsInt().descent / 2 - 8);
. (Good luck. :) )
public class CenteredImageSpan extends ImageSpan {
private WeakReference<Drawable> mDrawableRef;
// Extra variables used to redefine the Font Metrics when an ImageSpan is added
private int initialDescent = 0;
private int extraSpace = 0;
public CenteredImageSpan(Context context, final int drawableRes) {
super(context, drawableRes);
}
public CenteredImageSpan(Drawable drawableRes, int verticalAlignment) {
super(drawableRes, verticalAlignment);
}
@Override
public int getSize(Paint paint, CharSequence text,
int start, int end,
Paint.FontMetricsInt fm) {
Drawable d = getCachedDrawable();
Rect rect = d.getBounds();
// if (fm != null) {
// Paint.FontMetricsInt pfm = paint.getFontMetricsInt();
// // keep it the same as paint's fm
// fm.ascent = pfm.ascent;
// fm.descent = pfm.descent;
// fm.top = pfm.top;
// fm.bottom = pfm.bottom;
// }
if (fm != null) {
// Centers the text with the ImageSpan
if (rect.bottom - (fm.descent - fm.ascent) >= 0) {
// Stores the initial descent and computes the margin available
initialDescent = fm.descent;
extraSpace = rect.bottom - (fm.descent - fm.ascent);
}
fm.descent = extraSpace / 2 + initialDescent;
fm.bottom = fm.descent;
fm.ascent = -rect.bottom + fm.descent;
fm.top = fm.ascent;
}
return rect.right;
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text,
int start, int end, float x,
int top, int y, int bottom, @NonNull Paint paint) {
Drawable b = getCachedDrawable();
canvas.save();
// int drawableHeight = b.getIntrinsicHeight();
// int fontAscent = paint.getFontMetricsInt().ascent;
// int fontDescent = paint.getFontMetricsInt().descent;
// int transY = bottom - b.getBounds().bottom + // align bottom to bottom
// (drawableHeight - fontDescent + fontAscent) / 2; // align center to center
int transY = bottom - b.getBounds().bottom;
// this is the key
transY -= (paint.getFontMetricsInt().descent / 2 - 8);
// int bCenter = b.getIntrinsicHeight() / 2;
// int fontTop = paint.getFontMetricsInt().top;
// int fontBottom = paint.getFontMetricsInt().bottom;
// int transY = (bottom - b.getBounds().bottom) -
// (((fontBottom - fontTop) / 2) - bCenter);
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
// Redefined locally because it is a private member from DynamicDrawableSpan
private Drawable getCachedDrawable() {
WeakReference<Drawable> wr = mDrawableRef;
Drawable d = null;
if (wr != null)
d = wr.get();
if (d == null) {
d = getDrawable();
mDrawableRef = new WeakReference<>(d);
}
return d;
}
}
EDIT
I implemented above code like this:
Drawable myIcon = getResources().getDrawable(R.drawable.btn_feedback_yellow);
int width = (int) Functions.convertDpToPixel(75, getActivity());
int height = (int) Functions.convertDpToPixel(23, getActivity());
myIcon.setBounds(0, 0, width, height);
CenteredImageSpan btnFeedback = new CenteredImageSpan(myIcon, ImageSpan.ALIGN_BASELINE);
ssBuilder.setSpan(
btnFeedback, // Span to add
getString(R.string.text_header_answer).length() - 1, // Start of the span (inclusive)
getString(R.string.text_header_answer).length(), // End of the span (exclusive)
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);// Do not extend the span when text add later
Android Custom text View To hold images and text
Here is the solution I implemented.
Spanned spanned = null;
String messageCustomized = "<img src ='"+ WebConstant.IMAGE_BASE_URL +
part +"'/>";//WebConstant.IMAGE_BASE_URL + part;
Spanned span = Html.fromHtml(messageCustomized, new
URLImageParser(sentMessagesViewHolder.tvMessage, context), null);
if (spanned!=null) {
spanned = (Spanned) TextUtils.concat(spanned, span);
}else spanned= span;
if (spanned!=null) {
txtView.setText(spanned);
}
Image Getter
public class URLImageParser implements ImageGetter {
Context context;
View container;
private int imageSize = 20;
private int imageSizeDisplaySize = 20;
URLDrawable urlDrawable = null;
public URLImageParser(View container, Context context) {
this.context = context;
this.container = container;
imageSize = Utility.convertDpTopPixels(context, 20);
imageSizeDisplaySize = Utility.convertDpTopPixels(context, 35);
}
@Override
public Drawable getDrawable(final String url) {
String[] arr = url.split("/");
final String fileName = arr[arr.length - 1];
urlDrawable = new URLDrawable();
Drawable drawable = null;
if (Build.VERSION.SDK_INT >= 21)
drawable =
context.getDrawable(R.drawable.profile_main_placeholder);
else
drawable = context.getResources().getDrawable(R.drawable.profile_main_placeholder);
drawable.setBounds(0, 0, 0 + imageSize, 0 + imageSize);
urlDrawable.drawable = drawable;
Bitmap bitmap = null;
bitmap = ImageUtility.getImageFromSDCard(fileName);
if (bitmap != null) { // the bitmap is available
bitmap = RoundedImageView.getCroppedBitmap(bitmap, imageSize, imageSize, imageSize);
drawable = new BitmapDrawable(context.getResources(), bitmap);//ImageUtility.bitmapToDrawable(context,resource);
drawable.setBounds(0, 0, 0 + imageSize, 0 + imageSize); //set the correct bound according to the result from HTTP call
URLImageParser.this.urlDrawable.drawable = drawable;
} else
Glide.with(context)
.load(url)
.asBitmap()
.transform(new CircleTransform(context))
.override(imageSizeDisplaySize, imageSizeDisplaySize)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
// you can do something with loaded bitmap here
// .....
Drawable drawable = new BitmapDrawable(context.getResources(), resource);//ImageUtility.bitmapToDrawable(context,resource);
drawable.setBounds(0, 0, 0 + imageSize, 0 + imageSize); //set the correct bound according to the result from HTTP call
URLImageParser.this.urlDrawable.drawable = drawable;
URLImageParser.this.container.invalidate();
ImageUtility.saveImageToSDCard(resource, fileName);
}
});
return urlDrawable.drawable; //return reference to URLDrawable where We will change with actual image from the src tag
//}
}
}
Custom Bitmap Drawable
public class URLDrawable extends BitmapDrawable {
// the drawable that you need to set, you could set the initial drawing
// with the loading image if you need to
protected Drawable drawable;
@Override
public void draw(Canvas canvas) {
// override the draw to facilitate refresh function later
if(drawable != null) {
drawable.draw(canvas);
}
}
}
Combining an Image with Text inside a Button
You can use ImageSpan to add a drawable
in between text. Below is an example .
TextView textView=(TextView)findViewById(R.id.b1);
Spannable span = new SpannableString("G OL");
Drawable android = getResources().getDrawable(R.mipmap.ic_launcher);
android.setBounds(0, 0, 50,50);
ImageSpan image = new ImageSpan(android, ImageSpan.ALIGN_BASELINE);
span.setSpan(image, 1, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(span);
Below is the output . You can modify the bounds.
Image doesn't display in SpannableString with Image
create a SpannableStringBuilder to append multiple imagespan and text
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(edittext.getText());
builder.append(getFilterWithIcon("100", R.drawable.ic_feature_bed_s));
and finally set
editText.setText(builder);
Note though SpannableStringBuilder is an immutable class it can't be changed.
Android : Adding an imageview right at the end of a textview via ImageSpan and make the image clickable
Here is a more complete answer to your question. I use a drawable resource, but you can create a drawable from your bitmap. See the following code for a description. This code can be placed into the onCreate()
of your main activity (or elsewhere.)
// Get a string that can be spanned with an ImageSpan and a ClickableSpan.
SpannableString ss = new SpannableString("Some text ");
// This will be the image. I use a resource here, but there are constructors that can
// accept a Drawable. See BitmapDrawable at https://developer.android.com/reference/android/graphics/drawable/BitmapDrawable#BitmapDrawable(android.content.res.Resources,%20android.graphics.Bitmap)
ImageSpan imgSpan = new ImageSpan(this, R.drawable.ic_baseline_airplanemode_active_24, ImageSpan.ALIGN_CENTER);
ClickableSpan cs = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
Toast.makeText(MainActivity.this, "Clicked!", Toast.LENGTH_SHORT).show();
}
};
// The image will overlay the last blank in the text.
ss.setSpan(imgSpan, ss.length() - 1, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// The clickable span will overlay the image from the ImageSpan.
ss.setSpan(cs, ss.length() - 1, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Just a TextView.
TextView myView = findViewById(R.id.myView);
myView.setText(ss);
// Prevent the ImageSpan from showing a highlight on click.
myView.setHighlightColor(getResources().getColor(android.R.color.transparent));
// Make sure the TextView can be clicked.
myView.setMovementMethod(LinkMovementMethod.getInstance());
Related Topics
Difficulties with Calling an Android Ndk Function from Directly Delphi
Do X86 Android Avd's Work on Linux on Amd
How to Change Endianness Mid-Execution on Arm (Android/Linux)
Android Device Not Shown with Adb
How to Launch Termux Through Another Android App
Android Failed to Start Emulator:Cannot Run Program
How to Remove Strings from a Compiled Binary (.So)
How to Integrate Opencv into Qt Creator Android Project
Passing Data from Java Class to Web View HTML
Android Webview Err_Unknown_Url_Scheme
End Call in Android Programmatically
Notification to Restore a Task Rather Than a Specific Activity
Google Play Services in Emulator, Implementing Google Plus Login Button etc