天天看点

利用内存复用,图片分块加载 进行大图片的加载

package com.example.kotlindemo

import android.content.Context
import android.graphics.*
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.Scroller
import java.io.InputStream


//自定义 View 绘制 大图部分
//内存复用,图片分块加载


class MyView(context: Context?) : View(context), GestureDetector.OnGestureListener {

    lateinit var mRect:Rect;
  //  var BitmapFactory.Options:options;

    lateinit var options:BitmapFactory.Options;

    lateinit var mgestureDetector:GestureDetector;

    lateinit var mScroller: Scroller;
    var mViewWidth:Int=0;
    var mViewHeight:Int=0;
    var scale:Float=0.0f;
    init {
        init()
    }

    fun init(){
        mRect = Rect();//
        options=BitmapFactory.Options();
        mgestureDetector=GestureDetector(context,this)
        mScroller= Scroller(context)


    }

    override fun onShowPress(e: MotionEvent?) {
    }

    override fun onSingleTapUp(e: MotionEvent?): Boolean {
    }

    override fun onDown(e: MotionEvent?): Boolean {
        if(!mScroller.isFinished){
            //滑动时,强制停止
            mScroller.forceFinished(true)
        }
        return true;
    }

    override fun onFling(
        e1: MotionEvent?,
        e2: MotionEvent?,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        mScroller.fling(0,mRect.top,
        0, -velocityY.toInt(),0,0,0, (imageHeight-mViewHeight/scale).toInt()
        )
        return false
    }

    override fun computeScroll() {
        super.computeScroll()
        if(mScroller.isFinished){
            return;
        }
        if(mScroller.computeScrollOffset()){
            mRect.top=mScroller.currY;
            mRect.bottom= (mRect.top+mViewHeight/scale).toInt();
            invalidate()
        }

    }

    override fun onScroll(
        e1: MotionEvent?,
        e2: MotionEvent?,
        distanceX: Float,
        distanceY: Float
    ): Boolean {

        mRect.offset(0,distanceY.toInt());
        //超过图片的高度 显示图片的底部
        if(mRect.bottom>imageHeight){
            mRect.bottom=imageHeight;
            mRect.top= (imageHeight-(mViewHeight/scale)).toInt()
        }

        if(mRect.top<0){
            mRect.top=0;
            mRect.bottom= (mViewHeight/scale).toInt();
        }
    //   mRect.offset 是设置显示某一块 调用onDraw 重新绘制Rect区域。还是那一块内存,通过来设置mBitmap=mDecoder.decodeRegion(mRect,options)确定mRect显示哪一块区域
        invalidate()
        return false
    }

    override fun onLongPress(e: MotionEvent?) {
    }


    override fun onTouchEvent(event: MotionEvent?): Boolean {
        return mgestureDetector.onTouchEvent(event)
    }

    /**
     * 图片很大,必须计算加载部分,要得整体到宽高。
     *
     * 但图片太大,不能把整张图片加载入内存
     *
     * 为了方便,所以用流,(可以用地址,但最终源码还是用的流 BitmapFactory.decodeFile(""))
     */
     var imageWidth:Int=0;
    var imageHeight:Int=0;
    lateinit var mDecoder:BitmapRegionDecoder;


    public fun setImage(inputStreamImage: InputStream){
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeStream(inputStreamImage,null,options);
        imageWidth=options.outWidth;
        imageHeight=options.outHeight;

        //开启图片的内存复用
        options.inMutable=true;

        //设置图片格式( )565  像素点占用的位数小每个像素点由RGB组成,R 5位 G 6位 B 5位,   ARGB_8888 每个像素占用8位 ARGB_4444 每个像素占用4位
        options.inPreferredConfig=Bitmap.Config.RGB_565
        options.inJustDecodeBounds=false

        //创建区域解码器
        mDecoder= BitmapRegionDecoder.newInstance(inputStreamImage,false)
        /**
         * 测量和绘制
         */
        requestLayout()


    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //不需要根据测量模式来测量
        mViewHeight=measuredWidth;
        mViewHeight=measuredHeight;

        mRect.left=0;
        mRect.top=0;
        mRect.right=mViewWidth;
        scale=mViewWidth/imageWidth.toFloat();
        mRect.bottom=(mViewHeight/scale).toInt();

    }

    lateinit  var mBitmap:Bitmap;//
    lateinit var matrix_:Matrix;
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //复用内存 ,前面复用内存是开启(相当于开关)
        options.inBitmap=mBitmap
        //
        mBitmap=mDecoder.decodeRegion(mRect,options)
        //缩放矩阵
        matrix_=Matrix();//var matrix_:Matrix_=Matrix() ;会造成内存抖动,频繁的创建对象和被回收,但matrix_放在外面就不会,都是使用的同一块内存地址,在堆内存中多次创建,会覆盖,不会出现频繁的创建对象和回收,只会损坏性能,关系不大
        matrix_.setScale(scale,scale)
        canvas.drawBitmap(mBitmap,matrix,null)
    }



}