在很多情况下,尤其是电商类网站,都会有促销活动或者其他一类的活动,在UI设计上通常会出现以下设计:
以及以下设计:
针对第一种情况,标题和标签在一行且标题只有一行的情况下,我们可以使用两个控件,一个imageView(simpleDrawView),一个textView,并设置他们的位置关系即可。(或者drawableLeft)
但是大多数情况下并非是这样的,而是和图2一样,这样设置两个控件就不合适了,以及设置textView的drawableLeft,都是不合适的,在多行文本的情况下会和UI设计图有很大的出入。
解决方案
在百度或者google上,输入安卓图文混排,会出现很多的解决方案,无外乎三种
- webview加载html(或者textView加载html)
需要注意的是,并不是所有的 HTML 标签在 TextView 中都是支持的,且官方文档并没有明确的说明支持 HTML 标签列表,通过查看 Android 源代码,可以得到简单的支持列表。
<br>,< p>,< div align=>,< strong>, <b>, <em>, <cite>, <dfn>, <i>, <big>, <small>, <font size=>, <font color=>, <blockquote>, <tt>, <a href=>,
<u>, <sup>, <sub>, <h1>,<h2>,<h3>,<h4>,<h5>,<h6>, <img src=>, <strike>
fromHtml方法
fromHtml(String source, ImageGetter imageGetter,TagHandler tagHandler)
继承ImageGetter
继承于 ImageGetter,重写 getDrawable (String source) 方法。通过异步操作,读取本地/网络资源,获得drawable对象。
继承TagHandler
继承于 TagHandler,重写了 handleTag()方法。为了支持更多的标签,例如为了支持<ul><ol><dd>和<li>
标签,这四个标签是在 formHtml()方法中本身是不支持。
如果开发者认为安卓 TagHandler 提供的默认标签解析已经够用,直接在 fromHtml()方法中第三个参数的地方填写 null 既可。
最后,通过 formHtml()方法将 HTML 内容转化为可供显示的 SpannableString,将 SpannableString 通过 setText 方法放入 TextView 中,就可以显示图文并茂的内容了。
drawable属性
即textview的drawableft等设置图片方法
缺陷就是多行文本下,实现不了这种UI
Spannable使用
使用html或者自定义有点大马拉小车的感觉,drawable属性又不能实现效果,所以Spannable就派上用场了
setText(CharSequence text)中接收的是CharSequence。而SpannableString和SpannableStringBuilder是其实现类,是可以直接赋值的。并且两者的setSpan()方法可以设置一些格式对象(例如字体大小、下划线、替换为图片等),这就可以实现富文本了。
Spannable实现子类:SpannableString,SpannableStringBuilder(可变,类似于StringBuilder)。
Spannable中定义了抽象方法:setSpan(Object what, int start, int end, int flags)和removeSpan(Object what)。这两个方法实现了对字符串的灵活编辑。
在这里我们用到的就是imageSpan。
继承imageSpan实现自己的居中方案,因为谷歌并没有提供居中方案.
/**
* Created on 2017/6/13.
* <p>
* 实现图文混排图片文字居中方案
*/
public class CenterImageSpan extends ImageSpan {
public CenterImageSpan(Context context, int resourceId) {
super(context, resourceId);
}
public CenterImageSpan(Context context, Bitmap bitmap){
super(context,bitmap);
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
Drawable b = getDrawable();
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2;
canvas.save();
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
}
使用方法就是,加载本地图片
SpannableStringBuilder ssb = new SpannableStringBuilder(" " + " " + " "+entity.title);//两个空格是占位符,随后图片会将其替代,另一个空格是间距
ImageSpan imageSpan = new CenterImageSpan(context, R.drawable.jingdong_jingxuan_logo);
ssb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
title.setText(ssb);
加载网络图片也是一样的,无非是在下载回调中获取到bitmap,如下:
JDImageUtils.displayImage(url, simpleDraweeView, new JDImageLoadingListener() {
@Override
public void onLoadingStarted(String s, View view) {
}
@Override
public void onLoadingFailed(String s, View view, JDFailReason jdFailReason) {
simpleDraweeView.setVisibility(View.GONE);
titleView.setText(title);
}
@Override
public void onLoadingComplete(String s, View view, Bitmap bitmap) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(" " + " " + title);
CenterImageSpan imageSpan = new CenterImageSpan(context, scaleBitmap(bitmap, width, height));
spannableStringBuilder.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
titleView.setText(spannableStringBuilder);
simpleDraweeView.setVisibility(View.GONE);
}
@Override
public void onLoadingCancelled(String s, View view) {
}
});
}
public static Bitmap scaleBitmap(Bitmap bm, int newWidth, int newHeight) {
// 获得图片的宽高
int width = bm.getWidth();
int height = bm.getHeight();
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix,
true);
return newbm;
}
这个算是这种布局最合理的实现方式了