package com.example.picturetest;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import java.io.IOException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BigView bigView = findViewById(R.id.bigView);
try {
InputStream is = getAssets().open("big.jpg");
bigView.setImage(is);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.example.picturetest;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import androidx.annotation.RequiresApi;
import java.io.IOException;
import java.io.InputStream;
@RequiresApi(api = Build.VERSION_CODES.M)
public class BigView extends View implements GestureDetector.OnGestureListener,View.OnTouchListener{
private Rect mRect;
private BitmapFactory.Options mOptions;
private GestureDetector mGestureDector;
private Scroller mScrpiler;
private int mImageWidth;
private int mImageHeight;
private BitmapRegionDecoder mDecoder;
private int mViewWidth;
private int mViewHeight;
private float mScale;
private Bitmap mBitmap;
public BigView(Context context, Rect mRect) {
super(context);
}
public BigView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BigView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//手勢識別
}
//第二步,設置圖片得到圖片的位置
public void setImage(InputStream is){
mGestureDector = new GestureDetector(getContext(), this);
mScrpiler = new Scroller(getContext());
setOnTouchListener(this);
//第一步,設置BigView所需要的一些成員變量
mRect = new Rect();
//內存複用
mOptions = new BitmapFactory.Options();
//滾動類
//獲取圖片寬和高,注意不能將圖片整個加載進內存
BitmapFactory.decodeStream(is,null, mOptions);
mOptions.inJustDecodeBounds = true;
mImageWidth = mOptions.outWidth;
mImageHeight = mOptions.outHeight;
//開啓複用
mOptions.inMutable = true;
//設置格式爲RGB565
mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
mOptions.inJustDecodeBounds = false;
//區域解碼器
try {
mDecoder = BitmapRegionDecoder.newInstance(is,false);
} catch (IOException e) {
e.printStackTrace();
}
requestLayout();
}
//第三步 開始測量,得到view的狂傲,測量加載的圖片到底縮放成什麼樣子
@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);
// mRect = new Rect( 0,0,mImageWidth,(int)(mViewHeight/mScale));
}
//第四步,畫出具體的內容
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//判斷解碼是不是爲null,如果解碼器沒有拿到,表示沒有設置過圖片
if(mDecoder == null){
return;
}
//真正的內存複用
mOptions.inBitmap = mBitmap;
//指定解碼區域
mBitmap = mDecoder.decodeRegion(mRect,mOptions);
//得到一個矩陣進行縮放,相當於得到view的大小
Matrix matrix = new Matrix();
matrix.setScale(mScale,mScale);
canvas.drawBitmap(mBitmap,matrix,null);
}
//第五步,處理點擊事件
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mScrpiler.startScroll(0, 0, 0, 0);
//直接將事件交給手勢事件處理
return mGestureDector.onTouchEvent(motionEvent);
}
//第六步 手按下去
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//如果沒有停止 則強行停止
if(!mScrpiler.isFinished()){
mScrpiler.forceFinished(true);
}
//繼續接收後序事件
return true;
}
@Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
}
//第七步 處理滑動事件 e1 開始事件,手滑按下去開始獲取座標 e2獲取當前事件座標 xy xy軸移動的距離
// 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;
// }
@Override
//第八步,處理慣性問題
public boolean onFling(MotionEvent e1, MotionEvent e2,float valocityX,float velocityY ){
mScrpiler.fling(0,mRect.top,0,(int)-velocityY,0,0,0,mImageHeight - (int)(mViewHeight/mScale));
return false;
}
//第九步 處理計算結果
@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;
}
@Override
public void computeScroll() {
if(mScrpiler.isFinished()){
return;
}
if(mScrpiler.computeScrollOffset()){
mRect.top = mScrpiler.getCurrY();
mRect.bottom = mRect.top + (int)(mViewHeight/mScale);
//mRect = new Rect(0,mScrpiler.getCurrY(),0, mRect.top + (int)(mViewHeight/mScale));
invalidate();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.picturetest.BigView
android:id="@+id/bigView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>