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