android实现长图加载效果
程序员文章站
2022-04-10 09:35:59
长图加载要用到一个关键的类bitmapregiondecoder,长图加载会使用到bitmap内存复用, 比如view大小是440*654,图片的宽高是440*12000,...
长图加载要用到一个关键的类bitmapregiondecoder,长图加载会使用到bitmap内存复用, 比如view大小是440*654,图片的宽高是440*12000,那么这个时候就要获取图片的宽和高, 跟view的宽和高进行对比,获取到一个缩小比例,那么会得到宽一个比例,高一个比例,用大的比例作为缩放因子,然后配合手势滑动滑动长图
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.support.annotation.nullable; import android.util.attributeset; import android.util.log; import android.view.gesturedetector; import android.view.motionevent; import android.view.view; import android.widget.scroller; import java.io.ioexception; import java.io.inputstream; public class bigview extends view implements gesturedetector.ongesturelistener, view.ontouchlistener { private static final string tag = "bigview"; private scroller mscroller; private gesturedetector mgesturedetector; private bitmapfactory.options moptions; private rect mrect; 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); setontouchlistener(this); // 滑动帮助 mscroller = new scroller(context); } /** * 由使用者输入一张图片 输入流 * * @param is */ public void setimage(inputstream is) { //先读取原图片的 宽、高 moptions.injustdecodebounds = true; bitmapfactory.decodestream(is, null, moptions); 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的大小 * * @param widthmeasurespec * @param heightmeasurespec */ @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); //获得测量的view的大小 mviewwidth = getmeasuredwidth(); mviewheight = getmeasuredheight(); //如果解码器是null 表示没有设置过要现实的图片 if (null == mdecoder) { return; } //确定要加载的图片的区域 mrect.left = 0; mrect.top = 0; mrect.right = mimagewidth; // log.e(tag,"缩放因子="+(mviewwidth*1.0f/mimagewidth*1.0f)); // log.e(tag,"缩放因子="+(mviewheight*1.0f/mimageheight*1.0f)); //获得缩放因子 mscale = mviewwidth / (float) mimagewidth; // 需要加载的高 * 缩放因子 = 视图view的高 // x * mscale = mviewheight mrect.bottom = (int) (mviewheight / mscale); log.e(tag,"l="+mrect.left); log.e(tag,"t="+mrect.top); log.e(tag,"r="+mrect.right); log.e(tag,"b="+mrect.bottom); } /** * 把图片画上去 * * @param canvas */ @override protected void ondraw(canvas canvas) { super.ondraw(canvas); // 如果解码器是null 表示没有设置过要现实的图片 if (null == mdecoder) { return; } //复用上一张bitmap log.e(tag,"复用上一张bitmap="+bitmap); moptions.inbitmap = bitmap; //解码指定区域 bitmap = mdecoder.decoderegion(mrect, moptions); //使用矩阵 对图片进行 缩放 matrix matrix = new matrix(); matrix.setscale(mscale, mscale); //画出来 canvas.drawbitmap(bitmap, matrix, null); } /** * 手指按下屏幕的回调 * @param e * @return */ @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 void onlongpress(motionevent e) { } /** * 手指 不离开屏幕 拖动 * @param e1 手指按下去 的事件 -- 获取开始的坐标 * @param e2 当前手势事件 -- 获取当前的坐标 * @param distancex x轴 方向移动的距离 * @param distancey y方向移动的距离 * @return */ @override public boolean onscroll(motionevent e1, motionevent e2, float distancex, float distancey) { // 手指从下往上 图片也要往上 distancey是负数, top 和 bottom 在减 // 手指从上往下 图片也要往下 distancey是正数, top 和 bottom 在加 //改变加载图片的区域 mrect.offset(0, (int) distancey); //bottom大于图片高了, 或者 top小于0了 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 y * @return */ @override public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) { /** * startx: 滑动开始的x坐标 * starty: 滑动开始的y坐标 * 两个速度 * minx: x方向的最小值 * max 最大 * y */ //计算器 mscroller.fling(0,mrect.top, 0,(int)-velocityy, 0,0,0, mimageheight - (int) (mviewheight / mscale)); return false; } //获取计算结果并且重绘 @override public void computescroll() { //已经计算结束 return if (mscroller.isfinished()){ return; } //true 表示当前动画未结束 if (mscroller.computescrolloffset()){ // mrect.top = mscroller.getcurry(); mrect.bottom = mrect.top+ (int) (mviewheight / mscale); invalidate(); } } @override public boolean ontouch(view v, motionevent event) { //交由手势处理 return mgesturedetector.ontouchevent(event); } }
如果是面试关键二点,第一个要说出来这个类,第二个要知道使用了内存复用.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: FFmpeg 4.0.6 gcc编译脚本
推荐阅读
-
基于CSS3 animation动画属性实现轮播图效果
-
Android自定义view实现太极效果实例代码
-
Android 使用ViewPager实现轮播图效果
-
Android中TabLayout+ViewPager实现tab和页面联动效果
-
Android中实现记事本动态添加行效果
-
Android Recyclerview实现水平分页GridView效果示例
-
Android中Market的Loading效果实现方法
-
Android实现ListView异步加载图片的方法
-
Android XRecyclerView实现多条目加载
-
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】