好久好久没有学习了,每天在王者农药里浸泡着,终于上了王者段位之后,心里空空如也!!是时候开始学习了,向高级进发!!!
在学习之前,不使用第三方框架的情况下,会有:哇,这咋搞,直接OOM呀!一脸萌币
学习之后,我去,就这么简单???
总结一下很简单了:
原理:将图片分块加载,滑到哪一块,加载哪一块区域。
大致步骤: 声明 BitmapFactory.Options和Rect对象,对Options对象属性操作,获取图片信息和设置显示图片是否复用内存;对Rect对象的 left,top,right,bottom属性值操作,动态设置图片显示区域,使用构建的图片解码器获取 图片目标区域的bitmap,最终使用 cavers绘制就OK了,其他双击缩放和惯性滑动,在这个基础上拓展也很简单,是不是也有一种感觉:**,就这么简单?
实现步骤如下:
1.初始化成员变量
2.根据图片流 ,使用 BitmapFactory.Options对象 ,获取图片尺寸,
3.使用 option对象的 inMutable=true的属性,设置内存复用,
4.使用 mOptions.inPreferredConfig = Bitmap.Config.RGB_565 设置图片格式,
5.构建 图片解释器 :BitmapRegionDecoder.newInstance(bitmapInputStream, false);
6.获取屏幕尺寸,
7.声明 Rect对象,计算图片显示像素区域
8.设置 option对象的 bitmap数据,使用 cavers绘制区域图形
9.使用 手势处理类,处理滑动事件
来吧,展示
//第一步 初始化成员变量
private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
//显示区域
mRect = new Rect();
//bitmapFactory 的属性类
mOptions = new BitmapFactory.Options();
//手势识别对象
mGestureListener = new GestureDetector(context, this);
//设置点击事件
setOnTouchListener(this);
//滚动辅助类
mScroller = new Scroller(context);
}
/**
* 2.根据图片流 ,使用 BitmapFactory.Options对象 ,获取图片尺寸,
* 3.使用 option对象的 inMutable=true的属性,设置内存复用,
* 4.使用 mOptions.inPreferredConfig = Bitmap.Config.RGB_565 设置图片格式,
* 5.构建 图片解释器 :BitmapRegionDecoder.newInstance(bitmapInputStream, false);
*/
public void setImageIs(InputStream stream) {
//只获取 图片信息,不加载到内存里,节约内存空间
mOptions.inJustDecodeBounds = true;
//解析图片流信息
BitmapFactory.decodeStream(stream, null, mOptions);
//图片宽
mImageWidth = mOptions.outWidth;
//图片高
mImageHeight = mOptions.outHeight;
//开启复用
mOptions.inMutable = true;
//设置图片格式
mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
//关闭只读信息模式
mOptions.inJustDecodeBounds = false;
//声明 图片构造器
try {
mDecor = BitmapRegionDecoder.newInstance(stream, false);
} catch (IOException e) {
e.printStackTrace();
}
//刷新视图
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取屏幕尺寸信息
mWindowWidth = getMeasuredWidth();
mWindowHeight = getMeasuredHeight();
mRect.left = 0;
mRect.top = 0;
//设置显示区域
mRect.right = mImageWidth > mWindowWidth ? mWindowWidth : mImageWidth;
mRect.bottom = mImageHeight > mWindowHeight ? mWindowHeight : mImageHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取屏幕尺寸信息
mWindowWidth = getMeasuredWidth();
mWindowHeight = getMeasuredHeight();
mRect.left = 0;
mRect.top = 0;
//设置显示区域
mRect.right = mImageWidth > mWindowWidth ? mWindowWidth : mImageWidth;
mRect.bottom = mImageHeight > mWindowHeight ? mWindowHeight : mImageHeight;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDecor == null) {
throw new RuntimeException("还未设置图片???");
}
//设置图片 bitmap
mOptions.inBitmap = mBitmap;
mBitmap = mDecor.decodeRegion(mRect, mOptions);
Matrix matrix = new Matrix();
matrix.setScale(1f, 1f);
canvas.drawBitmap(mBitmap, matrix, null);
}
//将 时间传递 发给 收拾处理器
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureListener.onTouchEvent(event);
}
/**
* 处理滑动事件,动态设置mRect对象的区域范围,刷新视图
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
mRect.offset((int) distanceX, (int) distanceY);
if (mRect.left < 0) {
mRect.left = 0;
mRect.right = mWindowWidth;
}
if (mRect.top < 0) {
mRect.top = 0;
mRect.bottom = mWindowHeight;
}
if (mRect.right > mImageWidth) {
mRect.left = mImageWidth - mWindowWidth;
mRect.right = mImageWidth;
}
if (mRect.bottom > mImageHeight) {
mRect.top = mImageHeight - mWindowHeight;
mRect.bottom = mImageHeight;
}
invalidate();
return false;
}
整个类文件放出来:
package com.gerryrun.gerryandroiddemo.weight;
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.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import androidx.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
/**
* com.gerryrun.gerryandroiddemo.weight
* create by GerryRun
* email:[email protected]
* 2020-08-15 20:52
* Describe here: 大长图 加载原理(无缩放,无惯性滑动,//todo 有时间加上 缩放和惯性滑动)
* steps:
* 1.初始化成员变量
* 2.根据图片流 ,使用 BitmapFactory.Options对象 ,获取图片尺寸,
* 3.使用 option对象的 inMutable=true的属性,设置内存复用,
* 4.使用 mOptions.inPreferredConfig = Bitmap.Config.RGB_565 设置图片格式,
* 5.构建 图片解释器 :BitmapRegionDecoder.newInstance(bitmapInputStream, false);
* 6.获取屏幕尺寸,
* 7.声明 Rect对象,计算图片显示像素区域
* 8.设置 option对象的 bitmap数据,使用 cavers绘制区域图形
* 9.使用 手势处理类,处理滑动事件
*/
public class BigView extends View implements View.OnTouchListener, GestureDetector.OnGestureListener {
private Rect mRect;//显示区域
private BitmapFactory.Options mOptions;
private GestureDetector mGestureListener;
private int mImageWidth, mImageHeight;
private int mWindowWidth, mWindowHeight;
private BitmapRegionDecoder mDecor;
private Bitmap mBitmap;
private Scroller mScroller;
public BigView(Context context) {
this(context, null);
}
public BigView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs, defStyleAttr);
}
//第一步 初始化成员变量
private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
//显示区域
mRect = new Rect();
//bitmapFactory 的属性类
mOptions = new BitmapFactory.Options();
//手势识别对象
mGestureListener = new GestureDetector(context, this);
//设置点击事件
setOnTouchListener(this);
//滚动辅助类
mScroller = new Scroller(context);
}
//第二步 设置图片 获取图片信息
public void setImageIs(InputStream stream) {
//只获取 图片信息,不加载到内存里,节约内存空间
mOptions.inJustDecodeBounds = true;
//解析图片流信息
BitmapFactory.decodeStream(stream, null, mOptions);
//图片宽
mImageWidth = mOptions.outWidth;
//图片高
mImageHeight = mOptions.outHeight;
//开启复用
mOptions.inMutable = true;
//设置图片格式
mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
//关闭只读信息模式
mOptions.inJustDecodeBounds = false;
//声明 图片解码器
try {
mDecor = BitmapRegionDecoder.newInstance(stream, false);
} catch (IOException e) {
e.printStackTrace();
}
//刷新视图
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取屏幕尺寸信息
mWindowWidth = getMeasuredWidth();
mWindowHeight = getMeasuredHeight();
//设置显示区域
mRect.left = 0;
mRect.top = 0;
mRect.right = mImageWidth > mWindowWidth ? mWindowWidth : mImageWidth;
mRect.bottom = mImageHeight > mWindowHeight ? mWindowHeight : mImageHeight;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//图片解码器为空,就是意味着没有设置图片
if (mDecor == null) {
throw new RuntimeException("还未设置图片???");
}
//设置图片 bitmap
mOptions.inBitmap = mBitmap;
//解码出区域 图片对象
mBitmap = mDecor.decodeRegion(mRect, mOptions);
//矩阵对象
Matrix matrix = new Matrix();
//设置缩放倍数,当图片进行缩放时,计算缩放因子,设置就OK了
matrix.setScale(1f, 1f);
canvas.drawBitmap(mBitmap, matrix, null);
}
//将 时间传递 发给 收拾处理器
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureListener.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
if (!mScroller.isFinished()) {
//强制停止滚动
mScroller.forceFinished(true);
}
//消费点击事件
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
mRect.offset((int) distanceX, (int) distanceY);
if (mRect.left < 0) {
mRect.left = 0;
mRect.right = mWindowWidth;
}
if (mRect.top < 0) {
mRect.top = 0;
mRect.bottom = mWindowHeight;
}
if (mRect.right > mImageWidth) {
mRect.left = mImageWidth - mWindowWidth;
mRect.right = mImageWidth;
}
if (mRect.bottom > mImageHeight) {
mRect.top = mImageHeight - mWindowHeight;
mRect.bottom = mImageHeight;
}
invalidate();
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
//处理惯性滑动
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mScroller.fling(mRect.left, mRect.top, (int) -velocityX, (int) -velocityY, 0, mImageWidth, 0, mImageHeight);
return false;
}
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.isFinished()) {
return;
}
//滚动还没有结束
if (mScroller.computeScrollOffset()) {
mRect.left = mScroller.getCurrX();
mRect.top = mScroller.getCurrY();
mRect.right = mRect.left + mWindowWidth;
mRect.bottom = (mRect.top + mWindowHeight);
//上下 范围计算
if (mRect.bottom > mImageHeight) {
mRect.bottom = mImageHeight;
mRect.top = mImageHeight - mWindowHeight;
}
//左右 范围计算
if (mRect.right > mImageWidth) {
mRect.right = mImageWidth;
mRect.left = mImageWidth - mWindowWidth;
}
invalidate();
}
}
}
**!!就这么简单???
结合老婆生产之后,家庭成员之间关系的变化情况,我在想,如果以后我生了女儿,我会不会同意我的宝贝女儿找家里同胞兄弟个数大于一个的男朋友,我觉得我不会同意,绝对不会
本人家里有个哥哥,在这么一个上有老下有小的人生阶段,我心里苦水真的不知道向谁诉说,只能打碎牙齿往肚里咽吧,也许有一天我也会崩溃的坐在大首都的某个角落大哭一场,被人拍下上了抖音、快手吧,人生不易,爱父母,爱妻儿,好好学习且行且珍惜吧,谢谢你读完了这段话,