zoukankan      html  css  js  c++  java
  • android 基于Fresco的富文本展示

    由于应用中的数据大量采用富文本排版 所以需要客户端解析格式去显示

    虽然WebView 可以做到 可是其中的图片下载并没有没有通过我们自己的缓存机制

    在git上找到了一个基于picasso的RichText 

    替换成我们所使用的Fresco 运行起来 没有问题 比起WebView也要流畅很多

    所以分享一下实现的代码 有问题 互相帮助改进

    现存问题:不支持gif格式

    talk is cheap show me the code

    /**
     * Created by sunche on 15/11/10. coffee in code out!
     */
    public class RichText extends TextView {
    
        private Drawable placeHolder, errorImage;//占位图,错误图
        private OnImageClickListener onImageClickListener;//图片点击回调
        MultiDraweeHolder<GenericDraweeHierarchy> mMultiDraweeHolder;
        private int d_w = 200;
        private int d_h = 200;
    
        public RichText(Context context) {
            this(context, null);
            init(context, null);
        }
    
        public RichText(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
            init(context, attrs);
        }
    
        public RichText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs);
        }
    
        private void init(Context context, AttributeSet attrs) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RichText);
            placeHolder = typedArray.getDrawable(R.styleable.RichText_placeHolder);
            errorImage = typedArray.getDrawable(R.styleable.RichText_errorImage);
    
            d_w = typedArray.getDimensionPixelSize(R.styleable.RichText_default_width, d_w);
            d_h = typedArray.getDimensionPixelSize(R.styleable.RichText_default_height, d_h);
    
            if (placeHolder == null) {
                placeHolder = new ColorDrawable(Color.GRAY);
            }
            placeHolder.setBounds(0, 0, d_w, d_h);
            if (errorImage == null) {
                errorImage = new ColorDrawable(Color.GRAY);
            }
            errorImage.setBounds(0, 0, d_w, d_h);
            typedArray.recycle();
            initDraweeHolder();
        }
    
        private void initDraweeHolder() {
            mMultiDraweeHolder = new MultiDraweeHolder<>();
        }
    
    
        /**
         * 设置富文本
         *
         * @param text 富文本
         */
        public void setRichText(String text) {
            Spanned spanned = Html.fromHtml(text, asyncImageGetter, null);
            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 (onImageClickListener != null) {
                            onImageClickListener.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());
        }
    
        /**
         * 异步加载图片(依赖于fresco)
         */
        private Html.ImageGetter asyncImageGetter = new Html.ImageGetter() {
            @Override
            public Drawable getDrawable(String source) {
                Log.i("RichText", "asyncImageGetter getDrawable.source:" + source);
                final URLDrawable urlDrawable = new URLDrawable();
                GenericDraweeHierarchy mHierarchy = new GenericDraweeHierarchyBuilder(getResources())
                        .build();
                final DraweeHolder draweeHolder = new DraweeHolder<GenericDraweeHierarchy>(mHierarchy);
                mMultiDraweeHolder.add(draweeHolder);
                DraweeController controller = Fresco.newDraweeControllerBuilder()
                        .setUri(Uri.parse(source))
                        .setOldController(draweeHolder.getController())
                        .setControllerListener(new ControllerListener<ImageInfo>() {
                            @Override
                            public void onSubmit(String id, Object callerContext) {
                                urlDrawable.setBounds(placeHolder.getBounds());
                                urlDrawable.setDrawable(placeHolder);
                                RichText.this.setText(getText());
                            }
    
                            @Override
                            public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
                                final Drawable drawable = draweeHolder.getHierarchy().getTopLevelDrawable();
                                drawable.setBounds(0, 0, imageInfo.getWidth(), imageInfo.getHeight());
                                urlDrawable.setBounds(0, 0, imageInfo.getWidth(), imageInfo.getHeight());
                                urlDrawable.setDrawable(drawable);
                                RichText.this.setText(getText());
                                Log.i("RichText", "onFinalImageSet " + imageInfo.getWidth() + ",height:" + imageInfo.getHeight());
                            }
    
                            @Override
                            public void onIntermediateImageSet(String id, ImageInfo imageInfo) {
                                Log.i("RichText", "onIntermediateImageSet " + imageInfo.getWidth() + ",height:" + imageInfo.getHeight());
                            }
    
                            @Override
                            public void onIntermediateImageFailed(String id, Throwable throwable) {
                            }
    
                            @Override
                            public void onFailure(String id, Throwable throwable) {
                                urlDrawable.setBounds(errorImage.getBounds());
                                urlDrawable.setDrawable(errorImage);
                                RichText.this.setText(getText());
                            }
    
                            @Override
                            public void onRelease(String id) {
    
                            }
                        })
                        .build();
                draweeHolder.setController(controller);
    
                return urlDrawable;
            }
        };
    
        @Override
        protected boolean verifyDrawable(Drawable who) {
            if (who instanceof URLDrawable && mMultiDraweeHolder.verifyDrawable(((URLDrawable) who).getDrawable())) {
                return true;
            }
            // 对其他Drawable的验证逻辑
            return super.verifyDrawable(who);
        }
    
        private static final class URLDrawable extends BitmapDrawable {
            private Drawable drawable;
    
            @SuppressWarnings("deprecation")
            public URLDrawable() {
            }
    
            @Override
            public void draw(Canvas canvas) {
                if (drawable != null)
                    drawable.draw(canvas);
            }
    
            public void setDrawable(Drawable drawable) {
                this.drawable = drawable;
            }
    
            public Drawable getDrawable() {
                return drawable;
            }
        }
    
        public void setPlaceHolder(Drawable placeHolder) {
            this.placeHolder = placeHolder;
            this.placeHolder.setBounds(0, 0, d_w, d_h);
        }
    
        public void setErrorImage(Drawable errorImage) {
            this.errorImage = errorImage;
            this.errorImage.setBounds(0, 0, d_w, d_h);
        }
    
        public void setOnImageClickListener(OnImageClickListener onImageClickListener) {
            this.onImageClickListener = onImageClickListener;
        }
    
        public interface OnImageClickListener {
            /**
             * 图片被点击后的回调方法
             *
             * @param imageUrls 本篇富文本内容里的全部图片
             * @param position  点击处图片在imageUrls中的位置
             */
            void imageClicked(List<String> imageUrls, int position);
        }
    
        @Override
        public void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            mMultiDraweeHolder.onDetach();
        }
    
        @Override
        public void onStartTemporaryDetach() {
            super.onStartTemporaryDetach();
            mMultiDraweeHolder.onDetach();
        }
    
        @Override
        public void onAttachedToWindow() {
            super.onAttachedToWindow();
            mMultiDraweeHolder.onAttach();
        }
    
        @Override
        public void onFinishTemporaryDetach() {
            super.onFinishTemporaryDetach();
            mMultiDraweeHolder.onAttach();
        }
    }
        <declare-styleable name="RichText">
            <attr name="placeHolder" format="reference" />
            <attr name="errorImage" format="reference" />
            <attr name="default_width" format="dimension" />
            <attr name="default_height" format="dimension" />
        </declare-styleable>
  • 相关阅读:
    软件工程实践总结作业——个人作业
    第四次作业——个人作业——软件案例分析
    第三次作业——结对编程
    第二次作业——结对项目之需求分析与原型模型设计
    使用Git进行代码管理心得
    调研Android Studio开发环境的发展演变(附安装教程,多图)
    软件工程的实践项目的自我目标
    软件工程实践总结
    教师报课系统测试
    第四次个人作业--关于 微软必应词典客户端 的案例分析
  • 原文地址:https://www.cnblogs.com/waterbear/p/4954817.html
Copyright © 2011-2022 走看看