核心思想
1.Bitmap分区块加载 2.内存复用
构造方法
初始化一些成员变量
public MBigView(Context context) {
this(context,null);
}
public MBigView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public MBigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 图片绘制的区域
mRect = new Rect();
//Bitmap Options
mOptions = new BitmapFactory.Options();
//手势检测器
mGestureDetector = new GestureDetector(context,this);
//滚动器
mScroller = new Scroller(context);
//缩放手势检测器
mScaleGestureDetector = new ScaleGestureDetector(context,new ScaleGesture());
//监听触摸事件
setOnTouchListener(this);
}
设置图片方法setImage(InputStream),里面做了
1.获取图片宽高 2.开启复用 3.设置图片质量 4.创建区域解码器
public void setImage(InputStream is){
// 不加载进内存的情况下获取图片的宽和高;
mOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is,null,mOptions);
mImageWidth = mOptions.outWidth;
mImageHeight = mOptions.outHeight;
mOptions.inJustDecodeBounds = false;
// 开启复用
mOptions.inMutable = true;
// 设置图片格式
mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
// 图片由像素点组成;像素点由什么组成;argb 透明通道 红色 绿色 蓝色;
// 创建区域解码器
try {
mDecoder = BitmapRegionDecoder.newInstance(is,false);
} catch (IOException e) {
e.printStackTrace();
}
requestLayout();
}
onMeasure方法中,确定图片的加载区域,定义缩放因子
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mViewWidth = getMeasuredWidth();
mViewHeight = getMeasuredHeight();
// 确定图片的加载区域;
mRect.left = 0;
mRect.top = 0;
mRect.right = Math.min(mImageWidth,mViewWidth);
Log.e("xxxxxxx",mImageWidth+" "+mViewWidth);
mRect.bottom = Math.min(mImageHeight,mViewHeight);
// 再定义一个缩放因子
originalScale = mViewWidth/(float)mImageWidth;
mScale = originalScale;
}
onDraw方法,复用内存,使用区域解码器解码
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mDecoder == null){return;}
// 复用内存
mOptions.inBitmap = mBitmap;
//区域解码器,解码区域
mBitmap = mDecoder.decodeRegion(mRect,mOptions);
Matrix matrix = new Matrix();
// 缩放矩阵
tempScale = mViewWidth/(float)mRect.width();
Log.e("TAG","left: " + mRect.left + " right: " + mRect.right + "top: " + mRect.top + "bottom: " + mRect.bottom + "tempScale: " + tempScale);
matrix.setScale(tempScale,tempScale);
//绘制bitmap
canvas.drawBitmap(mBitmap,matrix,null);
}
双击放大,改变缩放值大小
@Override
public boolean onDoubleTap(MotionEvent e) {
// 双击放大图片;
if(mScale < originalScale*2){
mScale = originalScale*2;
}else{
mScale = originalScale;
}
Log.e("xxxxx mScale ","mScale = "+mScale+" originalScale = "+originalScale);
mRect.right = mRect.left+(int)(mViewWidth/mScale);
mRect.bottom = mRect.top+(int)(mViewHeight/mScale);
// 移动时,处理到达顶部和底部的情况
if(mRect.bottom > mImageHeight){
mRect.bottom = mImageHeight;
mRect.top = mImageHeight-(int)(mViewHeight/mScale);
}
if(mRect.top < 0){
mRect.top = 0;
mRect.bottom = (int)(mViewHeight/mScale);
}
if(mRect.right > mImageWidth){
mRect.right = mImageWidth;
mRect.left = mImageWidth-(int)(mViewWidth/mScale);
}
if(mRect.left < 0){
mRect.left = 0;
mRect.right = (int)(mViewWidth/mScale);
}
Log.e("xxxxx Rect ","mRect.Left = "+mRect.left+
" mRect.right = "+mRect.right+
" mRect.top = "+mRect.top+
" mRect.bottom = "+mRect.bottom);
invalidate();
return false;
}
滚动时注意处理边界条件
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//处理区域偏移
mRect.offset((int)distanceX,(int)distanceY);
//处理边界条件
if(mRect.bottom > mImageHeight){
mRect.bottom = mImageHeight;
mRect.top = mImageHeight-(int)(mViewHeight/mScale);
}
if(mRect.top < 0){
mRect.top = 0;
mRect.bottom = (int)(mViewHeight/mScale);
}
if(mRect.right > mImageWidth){
mRect.right = mImageWidth;
mRect.left = mImageWidth-(int)(mViewWidth/mScale);
}
if(mRect.left < 0){
mRect.left = 0;
mRect.right = (int)(mViewWidth/mScale);
}
invalidate();
return false;
}