自定义view富文本RichText

参考:http://www.cnblogs.com/waterbear/p/4954817.html

由于api接口传过来的是富文本,使用的图片加载框架是facebook的fesco ,在想能不能在imageGetter里面使用fresco处理图片信息。于是google了一下,发现有一个RichText的自定义view。但在使用的过程中,BitmapDrawable在draw()的时候draw不出来,于是对drawable做处理。

原来的UrlDrawable ,使用了 drawable.draw(canvas)方法。canvas.drawBitmap(mBitmap, 0, 0, getPaint());能不能代替呢

 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;
        }
    }

In general, drawing bitmaps is faster than drawing as with the right preparation, drawing a bitmap is just dumping memory to the screen. If you need to draw a scaled bitmap, then draw it as one using createScaledBitmap
rather than creating it then scaling it. You can achieve this by:
Bitmap myBitmap = BitmapFactory.decodeFile(myFile.getPath());myBitmap = myBitmap.createScaledBitmap(myBitmap, width, height, true);

The Android developers documentation on the above function
Calculating and drawing primitives while running takes calculations and when drawing many of them will decrease performance, so use more bitmaps where you can - but be careful of doing premature optimisation - there's no point creating lots of bitmaps if there's no need as there will not be a significance (i.e. noticable) performance increase.

draw bimap的话速度是比较快的。当计算绘制多个图元 的时候会降低性能,所以尽可能使用bitmap。

因此,可以断定是由于性能降低的问题导致draw不出来。于是修改成canvas.drawBitmap(mBitmap, 0, 0, getPaint())。

在使用fresco时候也遇到了问题,Postprocessor 返回的bitmap才是最终的bitmap,而draweeHolder.getHierarchy().getTopLevelDrawable()是一个ArrayDrawable,里面含有一个Drawable数组,数组中的某一个才是你的目标图片。
只能使用这个方法获取,最后在onFinalImageSet 更新。

ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(source))
                    .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)
                    .setPostprocessor(new BasePostprocessor() {


                        @Override
                        public void process(Bitmap bitmap) {
                            super.process(bitmap);

                            int height = Constant.ScreenWidth * bitmap.getHeight() / bitmap.getWidth();
                            Bitmap sizeBitmap = bitmapScale(bitmap, d_w, height);
                            myDrawable.setBitmap(sizeBitmap);
                            myDrawable.setBounds(0, 0, d_w, height);

                            bitmapList.add(sizeBitmap);

                        }

                    }).build();

源码在此:

public class RichText extends android.support.v7.widget.AppCompatTextView {


    private OnImageClickListener onImageClickListener;//图片点击回调
    private MultiDraweeHolder mMultiDraweeHolder;
    private int d_w = 200;
    private int d_h = 200;
    private List bitmapList = new ArrayList<>();

    private Bitmap placeHolderBitmap, errorBitmap;


    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);

        d_w = typedArray.getDimensionPixelSize(R.styleable.RichText_default_width, Constant.ScreenWidth);
        d_h = typedArray.getDimensionPixelSize(R.styleable.RichText_default_height, Constant.ScreenWidth / 2);


        placeHolderBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.default_logo);
        placeHolderBitmap = Bitmap.createScaledBitmap(placeHolderBitmap, d_w, d_h, true);


        errorBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.default_logo);
        errorBitmap = Bitmap.createScaledBitmap(placeHolderBitmap, d_w, d_h, true);


        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 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) {

            final URLDrawable myDrawable = new URLDrawable(null, null);

            GenericDraweeHierarchy mHierarchy = new GenericDraweeHierarchyBuilder(getResources())
                    .build();
            final DraweeHolder draweeHolder = new DraweeHolder<>(mHierarchy);
            mMultiDraweeHolder.add(draweeHolder);


            ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(source))
                    .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)
                    .setPostprocessor(new BasePostprocessor() {


                        @Override
                        public void process(Bitmap bitmap) {
                            super.process(bitmap);

                            int height = Constant.ScreenWidth * bitmap.getHeight() / bitmap.getWidth();
                            Bitmap sizeBitmap = bitmapScale(bitmap, d_w, height);
                            myDrawable.setBitmap(sizeBitmap);
                            myDrawable.setBounds(0, 0, d_w, height);

                            bitmapList.add(sizeBitmap);

                        }

                    }).build();


            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setOldController(draweeHolder.getController())
                    .setImageRequest(request)
                    .setControllerListener(new ControllerListener() {
                        @Override
                        public void onSubmit(String id, Object callerContext) {

                            myDrawable.setBitmap(placeHolderBitmap);
                            myDrawable.setBounds(0, 0, d_w, d_h);

                            RichText.this.setText(getText());
                        }


                        @Override
                        public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {

                            RichText.this.setText(getText());

                        }

                        @Override
                        public void onIntermediateImageSet(String id, ImageInfo imageInfo) {
                        }

                        @Override
                        public void onIntermediateImageFailed(String id, Throwable throwable) {
                        }

                        @Override
                        public void onFailure(String id, Throwable throwable) {

                            myDrawable.setBitmap(errorBitmap);
                            myDrawable.setBounds(0, 0, d_w, d_h);
                            RichText.this.setText(getText());

                        }

                        @Override
                        public void onRelease(String id) {

                        }
                    })
                    .build();
            draweeHolder.setController(controller);

            return myDrawable;
        }
    };


    private static Bitmap bitmapScale(Bitmap bitmap, int newWidth, int newHeight) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        // 计算缩放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight); //长和宽放大缩小的比例
        Bitmap sizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return sizeBitmap;
    }


    private static class URLDrawable extends BitmapDrawable {
        Bitmap mBitmap;
        Rect mSrcRect;
        Rect mDstRect;

        public URLDrawable(Resources res, Bitmap bitmap) {
            super(res, bitmap);
        }

        public void setSrcRect(Rect srcRect) {
            mSrcRect = srcRect;
        }

        public void setDstRect(Rect dstRect) {
            mDstRect = dstRect;
        }

        @Override
        public void draw(Canvas canvas) {
            super.draw(canvas);

            // 绘制 bitmap
            if (mBitmap != null) {
                if (mSrcRect != null && mDstRect != null) {

                    canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, getPaint());

                } else if (mDstRect != null) {

                    int width = mBitmap.getWidth();
                    int height = mBitmap.getHeight();

                    Rect srcRect = new Rect(0, 0, width, height);
                    canvas.drawBitmap(mBitmap, srcRect, mDstRect, getPaint());

                } else {

                    canvas.drawBitmap(mBitmap, 0, 0, getPaint());
                }
            }
        }

        public void setBitmap(Bitmap bitmap) {
            mBitmap = bitmap;
        }
    }


    public void setOnImageClickListener(OnImageClickListener onImageClickListener) {
        this.onImageClickListener = onImageClickListener;
    }

    public interface OnImageClickListener {
        /**
         * 图片被点击后的回调方法
         *
         * @param imageUrls 本篇富文本内容里的全部图片
         * @param position  点击处图片在imageUrls中的位置
         */
        void imageClicked(List imageUrls, int position);
    }


    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mMultiDraweeHolder.onDetach();
        recycleBitmap();

    }

    @Override
    public void onStartTemporaryDetach() {
        super.onStartTemporaryDetach();
        mMultiDraweeHolder.onDetach();
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        mMultiDraweeHolder.onAttach();
    }

    @Override
    public void onFinishTemporaryDetach() {
        super.onFinishTemporaryDetach();
        mMultiDraweeHolder.onAttach();
    }


    private void recycleBitmap() {

        Log.e("recycleBitmap", "recycleBitmap");

        if (placeHolderBitmap != null) {
            if (!placeHolderBitmap.isRecycled()) {
                placeHolderBitmap.recycle();
                placeHolderBitmap = null;
            }
        }

        if (errorBitmap != null) {
            if (!errorBitmap.isRecycled()) {
                errorBitmap.recycle();
                errorBitmap = null;
            }
        }


        for (Bitmap bitmap : bitmapList) {

            if (bitmap != null) {
                if (!bitmap.isRecycled()) {
                    bitmap.recycle();
                    bitmap = null;
                }
            }
        }

        System.gc();
    }


}

你可能感兴趣的:(自定义view富文本RichText)