自定義view富文本RichText

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

由于api接口傳過(guò)來(lái)的是富文本,使用的圖片加載框架是facebook的fesco ,在想能不能在imageGetter里面使用fresco處理圖片信息。于是google了一下,發(fā)現(xiàn)有一個(gè)RichText的自定義view。但在使用的過(guò)程中,BitmapDrawable在draw()的時(shí)候draw不出來(lái),于是對(duì)drawable做處理。

原來(lái)的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的話速度是比較快的。當(dāng)計(jì)算繪制多個(gè)圖元 的時(shí)候會(huì)降低性能,所以盡可能使用bitmap。

因此,可以斷定是由于性能降低的問(wèn)題導(dǎo)致draw不出來(lái)。于是修改成canvas.drawBitmap(mBitmap, 0, 0, getPaint())。

在使用fresco時(shí)候也遇到了問(wèn)題,Postprocessor 返回的bitmap才是最終的bitmap,而draweeHolder.getHierarchy().getTopLevelDrawable()是一個(gè)ArrayDrawable,里面含有一個(gè)Drawable數(shù)組,數(shù)組中的某一個(gè)才是你的目標(biāo)圖片。
只能使用這個(gè)方法獲取,最后在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;//圖片點(diǎn)擊回調(diào)
    private MultiDraweeHolder<GenericDraweeHierarchy> mMultiDraweeHolder;
    private int d_w = 200;
    private int d_h = 200;
    private List<Bitmap> 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<>();
    }


    /**
     * 設(shè)置富文本
     *
     * @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) {

            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<ImageInfo>() {
                        @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();
        // 計(jì)算縮放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight); //長(zhǎng)和寬放大縮小的比例
        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 {
        /**
         * 圖片被點(diǎn)擊后的回調(diào)方法
         *
         * @param imageUrls 本篇富文本內(nèi)容里的全部圖片
         * @param position  點(diǎn)擊處圖片在imageUrls中的位置
         */
        void imageClicked(List<String> 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();
    }


}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Outline 本文主要從以下三個(gè)大的方面來(lái)說(shuō)明一下2D Graphic 繪圖的一些相關(guān)函數(shù)及應(yīng)用。 Col...
    lee_3do閱讀 3,364評(píng)論 0 11
  • Correctness AdapterViewChildren Summary: AdapterViews can...
    MarcusMa閱讀 9,067評(píng)論 0 6
  • View的三大流程:測(cè)量,布局,繪制上篇Android自定義View學(xué)習(xí)(一)——準(zhǔn)備簡(jiǎn)單介紹了部分測(cè)量的知識(shí),后...
    英勇青銅5閱讀 12,526評(píng)論 12 24
  • 周末去看了《寵物大作戰(zhàn)》,觀影前想起之前的報(bào)道,由于《瘋狂動(dòng)物城》的大賣,導(dǎo)致動(dòng)畫開拓了新領(lǐng)域。滿懷期待,雖然全程...
    頑一閱讀 464評(píng)論 0 0
  • 默認(rèn)數(shù)據(jù)格式 默認(rèn)情況下,采用tornado的web框架運(yùn)行起來(lái)之后,任何訪問(wèn)都會(huì)直接在控制臺(tái)輸出日志信息,格式如...
    極光火狐貍閱讀 7,027評(píng)論 1 2

友情鏈接更多精彩內(nèi)容