android 加载长图

长图加载的自定义view。

总结:1.利用Options先得到图片的宽高。

2.通过计算view的宽高得到 缩放因子。

3.利用缩放因子,计算要加载的图片Rect。

4.利用 BitmapRegionDecoder 结合Rect 进行制定区域解码图片。

5.通过 Options.inMutable = true 和Options.inBitmap = bitmap 重复利用Bitmap内存

6.利用缩放因子进行Bitmap矩阵的绘制,达到完全显示图片的效果

package com.example.bigview

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

/**
 * 长图加载自定义 view
 */
class VerticalLoadBigView : View, GestureDetector.OnGestureListener {

    lateinit var bitmap: Bitmap
    private var mViewHeight: Int = 0
    var mViewWidth: Int = 0
    var mRect: Rect //要加载的图片的矩形区域

    var mOptions: BitmapFactory.Options //需要复用的

    var mGestureDetector: GestureDetector //手势识别

    var mImageWidth = 0
    var mImageHeight = 0

    lateinit var mDecoder: BitmapRegionDecoder

    var mScroller: Scroller //滑动帮助类

    var mScale: Float = 0.0f

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)

    constructor(context: Context, attributeSet: AttributeSet?, defS: Int) : super(
        context,
        attributeSet,
        defS
    ) {
        mRect = Rect()

        mOptions = BitmapFactory.Options()

        mGestureDetector = GestureDetector(context, this)

        mScroller = Scroller(context)
    }

    /**
     * 设置图片进来
     */
    fun setImage(inputStream: InputStream) {
        mOptions.inJustDecodeBounds = true
        BitmapFactory.decodeStream(inputStream, null, mOptions)
        //得到图片的宽高
        mImageWidth = mOptions.outWidth
        mImageHeight = mOptions.outHeight

        mOptions.inMutable = true //开启重用bitmap 必须与mOptions.bitmap = bitmap一起使用

        //设置格式
        mOptions.outConfig = Bitmap.Config.RGB_565

        mOptions.inJustDecodeBounds = false

        //创建一个区域解码器
        mDecoder = BitmapRegionDecoder.newInstance(inputStream, false)

        requestLayout()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        //得到View的宽高
        mViewWidth = measuredWidth
        mViewHeight = measuredHeight

        //获得缩放因子
        if (mImageHeight > mImageWidth) {
            mScale = (mViewWidth / mImageWidth).toFloat()
        } else {
            mScale = (mViewHeight / mImageHeight).toFloat()
        }


        //确定要加载的图片的矩形区域
        mRect.left = 0
        mRect.top = 0
        mRect.right = mImageWidth
        mRect.bottom = (mImageHeight / mScale).toInt()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        //解码图片的指定区域
        bitmap = mDecoder.decodeRegion(mRect, mOptions)

        //复用上一张bitmap的内存区域
        mOptions.inBitmap = bitmap


        //创建一个缩放比
        val matrix = Matrix()
        matrix.setScale(mScale, mScale)
        canvas?.drawBitmap(bitmap, matrix, null)
    }


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

    override fun onShowPress(e: MotionEvent?) {

    }

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

    override fun onDown(e: MotionEvent?): Boolean {
        if (!mScroller.isFinished) {
            //如果移动还没有停止,强制停止
            mScroller.forceFinished(true)
        }

        return true
    }

    /**
     * 处理惯性事件
     * velocaityX 计算像素点每秒移动的速度  得到的是一个速度值
     * velocaityY
     */
    override fun onFling(
        e1: MotionEvent?,
        e2: MotionEvent?,
        velocityX: Float,
        velocityY: Float
    ): Boolean {

        //做计算
        mScroller.fling(
            0, mRect.top,
            0, (-velocityY).toInt(),
            0, 0,
            0, mImageHeight - (mViewHeight / mScale).toInt()
        )
        return false
    }

    override fun computeScroll() {
        if (mScroller.isFinished) {
            return
        }
        //true 表示当前滑动还没有结束  就去计算 mRect的上下值
        if (mScroller.computeScrollOffset()) {
            mRect.top = mScroller.currY
            mRect.bottom = mRect.top + (mViewHeight / mScale).toInt()
            invalidate()
        }
    }

    /**
     * 处理滑动事件
     * e1 按下的 event
     * e2 移动的event
     * distanceX 左右移动的距离
     * distanceY 上下移动的距离
     */
    override fun onScroll(
        e1: MotionEvent?,
        e2: MotionEvent?,
        distanceX: Float,
        distanceY: Float
    ): Boolean {
        //设置偏移的距离
        mRect.offset(0, distanceY.toInt())

        //处理移动时已经移到了两个顶端的问题
        if (mRect.bottom > mImageHeight) {
            mRect.bottom = mImageHeight
            mRect.top = mImageHeight - (mViewHeight / mScale).toInt()
        }

        if (mRect.top < 0) {
            mRect.top = 0
            mRect.bottom = (mViewHeight / mScale).toInt()
        }

        invalidate()
        return false;
    }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值