获取网络图片的ImageSpan
2016-11-07 17:01
204 查看
获取网络图片的ImageSpan
获取网络图片的ImageSpan效果
代码
实现方式
原理
TextView做图文混排时可能用到Html下的ImageGetter工具或者ImageSpan。
ImageGetter获取网络图片的例子很多, 但是如果文本中不包含图片的宽高信息,那么考虑预留多少空间是挺麻烦的事。
本例使用ImageSpan+Glide获取网络图片, 适用于文本内容较短的场景(因为获取到图片后会刷新控件,内容多会卡顿)。图片加载库换成类似的也行, 原理都一样
效果
代码
/** * 获取网络图片的ImageSpan * Created by Yomii on 2016/10/13. */ public class UrlImageSpan extends ImageSpan { private String url; private TextView tv; private boolean picShowed; public UrlImageSpan(Context context, String url, TextView tv) { super(context, R.mipmap.pic_holder); this.url = url; this.tv = tv; } @Override public Drawable getDrawable() { if (!picShowed) { Glide.with(tv.getContext()).load(url).asBitmap().into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { Resources resources = tv.getContext().getResources(); int targetWidth = (int) (resources.getDisplayMetrics().widthPixels * 0.8); Bitmap zoom = zoom(resource, targetWidth); BitmapDrawable b = new BitmapDrawable(resources, zoom); b.setBounds(0, 0, b.getIntrinsicWidth(), b.getIntrinsicHeight()); Field mDrawable; Field mDrawableRef; try { mDrawable = ImageSpan.class.getDeclaredField("mDrawable"); mDrawable.setAccessible(true); mDrawable.set(UrlImageSpan.this, b); mDrawableRef = DynamicDrawableSpan.class.getDeclaredField("mDrawableRef"); mDrawableRef.setAccessible(true); mDrawableRef.set(UrlImageSpan.this, null); picShowed = true; tv.setText(tv.getText()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } }); } return super.getDrawable(); } /** * 按宽度缩放图片 * * @param bmp 需要缩放的图片源 * @param newW 需要缩放成的图片宽度 * * @return 缩放后的图片 */ public static Bitmap zoom(@NonNull Bitmap bmp, int newW) { // 获得图片的宽高 int width = bmp.getWidth(); int height = bmp.getHeight(); // 计算缩放比例 float scale = ((float) newW) / width; // 取得想要缩放的matrix参数 Matrix matrix = new Matrix(); matrix.postScale(scale, scale); // 得到新的图片 Bitmap newbm = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true); return newbm; } }
实现方式
先通过Uri或者ResId的构造传入一个占位图。在getDrawable这个方法中, 如果图片未加载, 那么异步获取图片, 否则直接返回父类。
成功获取到图片的回调中, 通过反射把占位图替换为获取到的图片, 然后刷新文本控件就可以。缩放部分不是核心代码,获取到图片怎么改都行。
原理
首先看下父类ImageSpan, 只有一个核心方法getDrawable, 其他都是通过不同方式获取图片的构造。@Override public Drawable getDrawable() { Drawable drawable = null; if (mDrawable != null) { drawable = mDrawable; } else if (mContentUri != null) { Bitmap bitmap = null; try { InputStream is = mContext.getContentResolver().openInputStream( mContentUri); bitmap = BitmapFactory.decodeStream(is); drawable = new BitmapDrawable(mContext.getResources(), bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); is.close(); } catch (Exception e) { Log.e("sms", "Failed to loaded content " + mContentUri, e); } } else { try { drawable = mContext.getDrawable(mResourceId); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } catch (Exception e) { Log.e("sms", "Unable to find resource: " + mResourceId); } } return drawable; }
这个方法中对应不同的构造获取一个Drawable并返回, 并且首先判断mDrawable属性, 也就是说我们把获取到的图片改成它就行了。
但是光改它还不行, 依然没有到核心方法draw(), 看一下它在父类中是如何被调用的。
在DynamicDrawableSpan的draw方法中,绘制的bitmap是从getCachedDrawable()方法中获取的。
可以看到在getCachedDrawable()里并不是优先调用getDrawable而是调用一个缓存弱引用mDrawableRef。
由于获取图片是异步的,因此这个mDrawableRef必定存在,它就是我们的占位图。于是只要在回调时把它置空并刷新控件,就能成功调用getDrawable,返回之前替换进去的目标图片。
@Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { Drawable b = getCachedDrawable(); canvas.save(); int transY = bottom - b.getBounds().bottom; if (mVerticalAlignment == ALIGN_BASELINE) { transY -= paint.getFontMetricsInt().descent; } canvas.translate(x, transY); b.draw(canvas); canvas.restore(); } private Drawable getCachedDrawable() { WeakReference<Drawable> wr = mDrawableRef; Drawable d = null; if (wr != null) d = wr.get(); if (d == null) { d = getDrawable(); mDrawableRef = new WeakReference<Drawable>(d); } return d; }
相关文章推荐
- Android学习笔记21:ImageView获取网络图片
- Android--消息机制--handler--getImageFromUrl--网络上获取图片
- 检测SDWebImage有没有缓存图片 IOS 获取网络图片大小
- c#获取网络图片 Image和byte[]数组的相互转换
- Android如何获取网络上的图片并且显示在ImageView上
- Android学习笔记21-ImageView获取网络图片
- 【Android开发】范例1-开启新线程获取网络图片并显示到ImageView中
- SDWebImage获取网络图片大小
- 不用sdwebimage获取网络图片
- 安卓开发中如何获取网络图片并设置到ImageView?
- Android学习笔记21:ImageView获取网络图片
- 检测SDWebImage有没有缓存图片 IOS 获取网络图片大小
- ImageView获取网络图片
- [第三方]SDWebImage获取网络图片控件的用法
- Android中关于ImageView网络获取的图片的缩放问题
- android 获取网络图片并在Imageview上显示
- listview中的imageview获取网络图片重复显示的问题
- android网络获取图片并保存在本地和获取手机SD卡中的图片显示到ImageView上及利用代码删除图片
- IOS 网络浅析-(六 网络图片获取之三方SDWebImage)
- 开启新线程获取网络图片并显示到ImageView中