public class BigView extends View implements GestureDetector.OnGestureListener, View.OnTouchListener {
private Rect mRect;
private BitmapFactory.Options mOptions;
private GestureDetector mGestureDetector;
private Scroller mScroller;
private int mImageWidth;
private int mImageHeight;
private BitmapRegionDecoder mDecoder;
private int mViewWidth;
private int mViewHeight;
private float mScale;
private Bitmap bitmap;
public BigView(Context context) {
this(context, null, 0);
}
public BigView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//指定要加載的區域
mRect = new Rect();
//需要複用
mOptions = new BitmapFactory.Options();
//手勢識別類
mGestureDetector = new GestureDetector(context, this);
//設置onTouchListener
setOnTouchListener(this);
//滑動幫助
mScroller = new Scroller(context);
}
/**
* 由使用者輸入一張圖片
*/
public void setImage(InputStream is) {
//先讀取原圖片的信息 高,寬
mOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, mOptions);
mImageWidth = mOptions.outWidth;
mImageHeight = mOptions.outHeight;
//開啓複用
mOptions.inMutable = true;
//設置格式成RGB_565
mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
mOptions.inJustDecodeBounds = false;
//創建一個區域解碼器
try {
mDecoder = BitmapRegionDecoder.newInstance(is, false);
} catch (IOException e) {
e.printStackTrace();
}
requestLayout();
}
/**
* 在測量的時候把我們需要的內存區域獲取到 存入到mRect中
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取測量的view的大小
mViewWidth = getMeasuredWidth();
mViewHeight = getMeasuredHeight();
//確定要加載的圖片的區域
mRect.left = 0;
mRect.top = 0;
mRect.right = mImageWidth;
//獲取一個縮放因子
mScale = mViewWidth / (float) mImageWidth;
//高度就根據縮放比進行獲取
mRect.bottom = (int) (mViewHeight / mScale);
}
/**
* 畫出內容
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//如果解碼器拿不到,表示沒有設置過要顯示的圖片
if (null == mDecoder) {
return;
}
//複用上一張bitmap
mOptions.inBitmap = bitmap;
//解碼指定的區域
bitmap = mDecoder.decodeRegion(mRect, mOptions);
//把得到的矩陣大小的內存進行縮放 得到view的大小
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
//畫出來
canvas.drawBitmap(bitmap, matrix, null);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
//交給手勢處理
return mGestureDetector.onTouchEvent(event);
}
/**
* 手按下的回調
*
* @param e
* @return
*/
@Override
public boolean onDown(MotionEvent e) {
//如果移動還沒有停止,強制停止
if (!mScroller.isFinished()) {
mScroller.forceFinished(true);
}
//繼續接收後續事件
return true;
}
/**
* @param e1 接下
* @param e2 移動
* @param distanceX 左右移動時的距離
* @param distanceY 上下移動時的距離
* @return
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//上下移動的時候,需要改變顯示區域 改mRect
mRect.offset(0, (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);
}
invalidate();
return false;
}
/**
* 處理慣性問題
*
* @param e1
* @param e2
* @param velocityX 每秒移動的x點
* @param velocityY
* @return
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//做計算
mScroller.fling(0, mRect.top,
0, (int) -velocityY,
0, 0,
0, mImageHeight - (int) (mViewHeight / mScale));
return false;
}
/*
使用上一個接口的計算結果
*/
@Override
public void computeScroll() {
if (mScroller.isFinished()) {
return;
}
//true 表示當前滑動還沒有結束
if (mScroller.computeScrollOffset()) {
mRect.top = mScroller.getCurrY();
mRect.bottom = mRect.top + (int) (mViewHeight / mScale);
invalidate();
}
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
}