android textview显示GIF解决花屏问题,使用Glide4.0+,别犹豫,全网只有我这有写

本文介绍了如何在Android应用中使用Glide4.0来解决TextView显示GIF时出现的花屏问题。通过自定义TextView和Html.ImageGetter,实现了点击事件以及图片资源的加载和适配。遇到类似问题的开发者可以通过Glide的GifViewTarget和BitmapTarget来优化GIF显示。完整代码和示例可在提供的链接中查看。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Glide无疑是一个好东西,自从它被google推荐以来,我就一直钟情与它,不离不弃。

不过这家伙很淘气,API变的太快了,导致因为某些原因被迫升级以后,还得挨个改它的很多调用。

最近我碰到一个项目,类似今日头条,要求在文章详情中,显示文字、图片、GIF等。

由于前期架构的问题,没有去用webview,直接作死的去挑战textview,利用HTML.fromHtml()的方式去自定义Spanned满足需求。不过缺点也很明显,由于没有写重用和资源回收机制,当图片过多时,直接OOM....如果有机会去完善这个框架,我会去考虑加入资源回收和重用,毕竟每张图片即使它压缩了,依旧蛮耗内存的。


言归正传,先讲重点,后上代码。

1、自定义textview,包括维护它的点击事件,这样每张图都可以点开。

核心代码:

在自定义的textview里,定义一个setRichText的方法,用于设置ImageGetter和点击事件。

public void setRichText(String text) {
        Html.ImageGetter imgGetter = new UrlImageGetter(this, getContext()); //设置ImageGetter
     
        Spanned spanned = Html.fromHtml(text, imgGetter, new HtmlTagHandler());
        SpannableStringBuilder spannableStringBuilder;
        if (spanned instanceof SpannableStringBuilder) {
            spannableStringBuilder = (SpannableStringBuilder) spanned;
        } else {
            spannableStringBuilder = new SpannableStringBuilder(spanned);
        }
        // 处理图片的点击事件
        ImageSpan[] imageSpans = spannableStringBuilder.getSpans(0, spannableStringBuilder.length(), ImageSpan.class);
        final List<String> imageUrls = new ArrayList<>();
        for (int i = 0, size = imageSpans.length; i < size; i++) {
            ImageSpan imageSpan = imageSpans[i];
            String imageUrl = imageSpan.getSource();
            int start = spannableStringBuilder.getSpanStart(imageSpan);
            int end = spannableStringBuilder.getSpanEnd(imageSpan);
            imageUrls.add(imageUrl);
            final int finalI = i;
            ClickableSpan clickableSpan = new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    if (onRichTextImageClickListener != null) {
                        onRichTextImageClickListener.imageClicked(imageUrls, finalI);
                    }
                }
            };
            ClickableSpan[] clickableSpans = spannableStringBuilder.getSpans(start, end, ClickableSpan.class);
            if (clickableSpans != null && clickableSpans.length != 0) {
                for (ClickableSpan cs : clickableSpans) {
                    spannableStringBuilder.removeSpan(cs);
                }
            }
            spannableStringBuilder.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        super.setText(spanned);
        setMovementMethod(LinkMovementMethod.getInstance());
    }


2、自定义Html.ImageGetter,它会解析HTML中的图片部分,每当发现是图片资源时,则进入它的代码,进行图片的相关处理。我们自定义它主要是用来启动GIF动画以及重设图片大小。

核心代码:

(1)在重写的getDrawable方法中,利用Glide加载图片,并将加载好的图片选择是显示在GifViewTarget中还是BitmapTarget中

@Override
    public Drawable getDrawable(String source) {
        
        if (isGif(source)) {
            final UrlDrawable2 urlDrawable2 = new UrlDrawable2();
            Glide.with(mContext).asGif().load(source).into(new GifViewTarget(urlDrawable2));
            return urlDrawable2;
        } else {
            final UrlDrawable urlDrawable = new UrlDrawable();
            Glide.with(mContext).asBitmap().load(source).into(new BitmapTartget(urlDrawable));
            return urlDrawable;
        }
    }

(2)自定义BitmapTarget和GifViewTarget:

private class BitmapTartget extends SimpleTarget<Bitmap> {

        private final UrlDrawable urlDrawable;

        public BitmapTartget(UrlDrawable drawable) {
            this.urlDrawable = drawable;
        }

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
            float scaleWidth = ((float) mWidth) / resource.getWidth();
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleWidth);
            resource.setConfig(Bitmap.Config.ARGB_4444);
            resource = Bitmap.createBitmap(resource, 0, 0,
                    resource.getWidth(), resource.getHeight(),
                    matrix, true);
            urlDrawable.bitmap = resource;
            urlDrawable.setBounds(0, 0, resource.getWidth(),
                    resource.getHeight());
            mTextView.invalidate();
            mTextView.setText(mTextView.getText());
        }
    }
private class GifViewTarget extends SimpleTarget<GifDrawable> {

        private final UrlDrawable2 mDrawable;

        private GifViewTarget(UrlDrawable2 drawable) {
            mTargets.add(this);
            this.mDrawable = drawable;
        }

        private Request request;

        @Override
        public Request getRequest() {
            return request;
        }

        @Override
        public void onResourceReady(GifDrawable resource, Transition<? super GifDrawable> transition) {
            Rect rect;
            if (resource.getIntrinsicWidth() > 100) {
                float width;
                float height;
                Log.e("koen", "resource width is " + resource.getIntrinsicWidth());
                Log.e("koen", "mTextView width is " + mWidth);
                if (resource.getIntrinsicWidth() >= mWidth) {
                    float downScale = (float) resource.getIntrinsicWidth() / mWidth;
                    width = (float) resource.getIntrinsicWidth() / (float) downScale;
                    height = (float) resource.getIntrinsicHeight() / (float) downScale;
                } else {
                    float multiplier = (float) mWidth / resource.getIntrinsicWidth();
                    width = (float) resource.getIntrinsicWidth() * (float) multiplier;
                    height = (float) resource.getIntrinsicHeight() * (float) multiplier;
                }
                Log.e("koen", "Final view width is " + width);
                rect = new Rect(0, 0, Math.round(width), Math.round(height));
            } else {
                Log.e("koen", "else view width");
                rect = new Rect(0, 0, resource.getIntrinsicWidth() * 2, resource.getIntrinsicHeight() * 2);
            }
            resource.setBounds(rect);
            mDrawable.setBounds(rect);
            mDrawable.setDrawable(resource);
            //if (resource.isRunning()) {
            mDrawable.setCallback(get(mTextView));
            resource.setLoopCount(GifDrawable.LOOP_FOREVER);
            resource.start();
            // }
            mTextView.setText(mTextView.getText());
            mTextView.invalidate();
        }

demo已上传,地址是:http://download.youkuaiyun.com/download/xuehaiwuya1212/10206290

最后,感谢两位大神给我的思路...大神的文章出处已经失传了...我贴不出来


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值