Android平台上大长图(图片很大的那种)的加载原理和方式

Android平台上大长图(图片很大的那种)的加载原理和方式

好久好久没有学习了,每天在王者农药里浸泡着,终于上了王者段位之后,心里空空如也!!是时候开始学习了,向高级进发!!!

学习感想:

在学习之前,不使用第三方框架的情况下,会有:哇,这咋搞,直接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.使用 手势处理类,处理滑动事件

来吧,展示

初始化成员变量、根据图片流 ,使用 BitmapFactory.Options对象 ,获取图片尺寸,

//第一步 初始化成员变量

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();

}

获取屏幕尺寸,声明 Rect对象,计算图片显示像素区域

@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;

}

设置 option对象的 bitmap数据,使用 cavers绘制区域图形

@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:gerryin@163.com

* 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();

}

}

}

**!!就这么简单???

有缘人,下面这段话是我心里的苦水,只能在这儿诉说一下

学习感想:正文开始

结合老婆生产之后,家庭成员之间关系的变化情况,我在想,如果以后我生了女儿,我会不会同意我的宝贝女儿找家里同胞兄弟个数大于一个的男朋友,我觉得我不会同意,绝对不会 本人家里有个哥哥,在这么一个上有老下有小的人生阶段,我心里苦水真的不知道向谁诉说,只能打碎牙齿往肚里咽吧,也许有一天我也会崩溃的坐在大首都的某个角落大哭一场,被人拍下上了抖音、快手吧,人生不易,爱父母,爱妻儿,好好学习且行且珍惜吧,谢谢你读完了这段话,

相关推荐

健身记录软件有哪些?健身训练记录软件推荐
十种营养又省时的即食冲饮推荐 上班族必备的平价好喝冲调饮品分享
2017传奇手游哪个好玩 玩不腻的传奇手游盘点