android实现长图加载效果
长图加载要用到一个关键的类BitmapRegionDecoder,长图加载会使用到bitmap内存复用,比如view大小是440*654,图片的宽高是440*12000,那么这个时候就要获取图片的宽和高,跟view的宽和高进行对比,获取到一个缩小比例,那么会得到宽一个比例,高一个比例,用大的比例作为缩放因子,然后配合手势滑动滑动长图
importandroid.content.Context; importandroid.graphics.Bitmap; importandroid.graphics.BitmapFactory; importandroid.graphics.BitmapRegionDecoder; importandroid.graphics.Canvas; importandroid.graphics.Matrix; importandroid.graphics.Rect; importandroid.support.annotation.Nullable; importandroid.util.AttributeSet; importandroid.util.Log; importandroid.view.GestureDetector; importandroid.view.MotionEvent; importandroid.view.View; importandroid.widget.Scroller; importjava.io.IOException; importjava.io.InputStream; publicclassBigViewextendsViewimplementsGestureDetector.OnGestureListener,View.OnTouchListener{ privatestaticfinalStringTAG="BigView"; privateScrollermScroller; privateGestureDetectormGestureDetector; privateBitmapFactory.OptionsmOptions; privateRectmRect; privateintmImageWidth; privateintmImageHeight; privateBitmapRegionDecodermDecoder; privateintmViewWidth; privateintmViewHeight; privatefloatmScale; privateBitmapbitmap; publicBigView(Contextcontext){ this(context,null,0); } publicBigView(Contextcontext,@NullableAttributeSetattrs){ this(context,attrs,0); } publicBigView(Contextcontext,@NullableAttributeSetattrs,intdefStyleAttr){ super(context,attrs,defStyleAttr); //指定要加载的矩形区域 mRect=newRect(); //解码图片的配置 mOptions=newBitmapFactory.Options(); //手势 mGestureDetector=newGestureDetector(context,this); setOnTouchListener(this); //滑动帮助 mScroller=newScroller(context); } /** *由使用者输入一张图片输入流 * *@paramis */ publicvoidsetImage(InputStreamis){ //先读取原图片的宽、高 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(IOExceptione){ e.printStackTrace(); } requestLayout(); } /** *测量view的大小 * *@paramwidthMeasureSpec *@paramheightMeasureSpec */ @Override protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){ 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); } /** *把图片画上去 * *@paramcanvas */ @Override protectedvoidonDraw(Canvascanvas){ super.onDraw(canvas); //如果解码器是null表示没有设置过要现实的图片 if(null==mDecoder){ return; } //复用上一张bitmap Log.e(TAG,"复用上一张bitmap="+bitmap); mOptions.inBitmap=bitmap; //解码指定区域 bitmap=mDecoder.decodeRegion(mRect,mOptions); //使用矩阵对图片进行缩放 Matrixmatrix=newMatrix(); matrix.setScale(mScale,mScale); //画出来 canvas.drawBitmap(bitmap,matrix,null); } /** *手指按下屏幕的回调 *@parame *@return */ @Override publicbooleanonDown(MotionEvente){ //如果滑动还没有停止强制停止 if(!mScroller.isFinished()){ mScroller.forceFinished(true); } //继续接收后续事件 returntrue; } @Override publicvoidonShowPress(MotionEvente){ } @Override publicbooleanonSingleTapUp(MotionEvente){ returnfalse; } @Override publicvoidonLongPress(MotionEvente){ } /** *手指不离开屏幕拖动 *@parame1手指按下去的事件--获取开始的坐标 *@parame2当前手势事件--获取当前的坐标 *@paramdistanceXx轴方向移动的距离 *@paramdistanceYy方向移动的距离 *@return */ @Override publicbooleanonScroll(MotionEvente1,MotionEvente2,floatdistanceX,floatdistanceY){ //手指从下往上图片也要往上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(); returnfalse; } /** *手指离开屏幕滑动惯性 *@parame1 *@parame2 *@paramvelocityX速度每秒x方向移动的像素 *@paramvelocityYy *@return */ @Override publicbooleanonFling(MotionEvente1,MotionEvente2,floatvelocityX,floatvelocityY){ /** *startX:滑动开始的x坐标 *startY:滑动开始的y坐标 *两个速度 *minX:x方向的最小值 *max最大 *y */ //计算器 mScroller.fling(0,mRect.top, 0,(int)-velocityY, 0,0,0, mImageHeight-(int)(mViewHeight/mScale)); returnfalse; } //获取计算结果并且重绘 @Override publicvoidcomputeScroll(){ //已经计算结束return if(mScroller.isFinished()){ return; } //true表示当前动画未结束 if(mScroller.computeScrollOffset()){ // mRect.top=mScroller.getCurrY(); mRect.bottom=mRect.top+(int)(mViewHeight/mScale); invalidate(); } } @Override publicbooleanonTouch(Viewv,MotionEventevent){ //交由手势处理 returnmGestureDetector.onTouchEvent(event); } }
如果是面试关键二点,第一个要说出来这个类,第二个要知道使用了内存复用.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。