Android长图加载 - 利用Bitmap Options

class BigView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr), GestureDetector.OnGestureListener, View.OnTouchListener {
    //要加载的图片范围
    private val mRect by lazy {
        Rect()
    }
    //Bitmap配置类
    private val mOptions by lazy {
        BitmapFactory.Options().apply {
            //开启内存复用
            inMutable = true
            //设置图片格式为565
            inPreferredConfig = Bitmap.Config.RGB_565
        }
    }
    //手势监听
    private val mGestureDetector by lazy {
        GestureDetector(context, this)
    }
    //Scroller,利用这个类进行滑动
    private val mScroller by lazy {
        Scroller(context)
    }
    //矩阵,处理图片的缩放
    private val mMatrix by lazy {
        Matrix()
    }
    //图片宽高
    private var mImageWidth: Int = 0
    private var mImageHeight: Int = 0
    //展示图片的View的宽高
    private var mViewWidth: Int = 0
    private var mViewHeight: Int = 0
    //缩放因子
    private var mScale: Float = 0f
    //图片解码器
    private var mDecoder: BitmapRegionDecoder? = null
    //复用的Bitmap
    private var mBitmap: Bitmap? = null

    init {
        setOnTouchListener(this)
    }

    //设置图片
    fun setImage(inputStream: InputStream) {
        //设置inJustDecodeBounds,让其不加载进内存也能获得图片相关信息
        mOptions.inJustDecodeBounds = true
        BitmapFactory.decodeStream(inputStream, null, mOptions)
        //获取图片宽高
        mImageWidth = mOptions.outWidth
        mImageHeight = mOptions.outHeight
        mOptions.inJustDecodeBounds = false

        //获取图片解码器
        try {
            mDecoder = BitmapRegionDecoder.newInstance(inputStream, false)
        } catch (e: IOException) {
        }

        requestLayout()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //获取View视图的宽高
        mViewWidth = measuredWidth
        mViewHeight = measuredHeight

        //计算图片的缩放系数
        mScale = mViewWidth.div(mImageWidth.toFloat())

        //赋值给图片要加载区域的Rect,要加载进来的高度需要根据缩放系数计算
        //缩放之后肯定能够展示更多的高度,所以要算出缩放前需要加载的图片高度
        mRect.set(0, 0, mImageWidth, mViewHeight.div(mScale).toInt())
    }

    //绘制图片
    override fun onDraw(canvas: Canvas?) {
        if (mDecoder == null) {
            return
        }

        //设置复用的Bitmap
        mOptions.inBitmap = mBitmap
        //解码器对图片加载的区域进行解码
        mBitmap = mDecoder!!.decodeRegion(mRect, mOptions)
        //设置矩阵
        mMatrix.setScale(mScale, mScale)
        //在展示的区域内绘制这个图片,区域之外的图片不会绘制
        mBitmap?.let {
            canvas?.drawBitmap(it, mMatrix, null)
        }
    }

    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
        //交给手势识别去处理
        mGestureDetector.onTouchEvent(event)
        return true
    }

    override fun onDown(e: MotionEvent?): Boolean {
        //手指按下的时候,让滑动停止
        if (!mScroller.isFinished) {
            mScroller.forceFinished(true)
        }
        return true
    }

    override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
        //将矩形偏移
        mRect.offset(0, distanceY.toInt())

        //处理滑动到顶部和底部的情况
        if (mRect.top < 0) {
            mRect.top = 0
            mRect.bottom = mViewHeight.div(mScale).toInt()
        }

        if (mRect.bottom > mImageHeight) {
            mRect.bottom = mImageHeight
            mRect.top = mImageHeight.minus(mViewHeight.div(mScale)).toInt()
        }

        invalidate()
        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, mImageHeight.minus(mViewHeight.div(mScale)).toInt())
        return true
    }

    override fun computeScroll() {
        if (mScroller.isFinished) {
            return
        }

        if (mScroller.computeScrollOffset()) {
            mRect.top = mScroller.currY
            mRect.bottom = mRect.top.plus(mViewHeight.div(mScale).toInt())
            invalidate()
        }
    }

    override fun onShowPress(e: MotionEvent?) {
    }

    override fun onSingleTapUp(e: MotionEvent?): Boolean = true

    override fun onLongPress(e: MotionEvent?) {
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值