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>