Android長圖加載優化

實現長圖加載基本思路:

1、獲取長圖的寬,高

2、獲取view的寬、高

3、根據長度的寬和view的寬計算縮放比例,從而計算待縮放區域rect

4、設定手勢,動態獲取待縮放區域

5、對制定的區域進行縮放

Android長圖加載優化

長圖加載

代碼

自定義view實現長圖加載,其中使用了內存複用的功能,優化了內存,具體可以參考代碼。

public class BigView extends View implements GestureDetector.OnGestureListener,View.OnTouchListener{
private Rect mRect;
private BitmapFactory.Options mOptions;
private GestureDetector mGestureDetector;
private Scroller mScroller;
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);
//設置onTouchListener
setOnTouchListener(this);
//滑動幫助
mScroller=new Scroller(context);
}
/**
* 由使用者輸入一張圖片
*/
public void setImage(InputStream is){
//先讀取原圖片的信息 高,寬

mOptions.inJustDecodeBounds=true;
BitmapFactory.decodeStream(is,null,mOptions);
mImageWidth=mOptions.outWidth;
mImageHeight=mOptions.outHeight;
//開啟複用
mOptions.inMutable=true;
//設置格式成RGB_565
mOptions.inPreferredConfig=Bitmap.Config.RGB_565;
mOptions.inJustDecodeBounds=false;
//創建一個區域解碼器
try {
mDecoder=BitmapRegionDecoder.newInstance(is,false);
} catch (IOException e) {
e.printStackTrace();
}
requestLayout();
}
/**
* 在測量的時候把我們需要的內存區域獲取到 存入到mRect中
*/
@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);
}
/**
* 畫出內容
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//如果解碼器拿不到,表示沒有設置過要顯示的圖片

if(null==mDecoder){
return;
}
//複用上一張bitmap
mOptions.inBitmap=bitmap;
//解碼指定的區域
bitmap=mDecoder.decodeRegion(mRect,mOptions);
//把得到的矩陣大小的內存進行縮放 得到view的大小
Matrix matrix=new Matrix();
matrix.setScale(mScale,mScale);
//畫出來
canvas.drawBitmap(bitmap,matrix,null);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
//交給手勢處理
return mGestureDetector.onTouchEvent(event);
}
/**
* 手按下的回調
* @param e
* @return
*/
@Override
public boolean onDown(MotionEvent e) {
//如果移動還沒有停止,強制停止
if(!mScroller.isFinished()){
mScroller.forceFinished(true);
}
//繼續接收後續事件
return true;
}
/**
*
* @param e1 接下
* @param e2 移動
* @param distanceX 左右移動時的距離
* @param distanceY 上下移動時的距離
* @return
*/
@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;
}
/**
* 處理慣性問題
* @param e1
* @param e2
* @param velocityX 每秒移動的x點
* @param velocityY
* @return
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//做計算
mScroller.fling(0,mRect.top,
0,(int)-velocityY,
0,0,
0,mImageHeight-(int)(mViewHeight/mScale));
return false;
}
/*
使用上一個接口的計算結果
*/
@Override
public void computeScroll() {
if(mScroller.isFinished()){
return;
}
//true 表示當前滑動還沒有結束
if(mScroller.computeScrollOffset()){
mRect.top=mScroller.getCurrY();
mRect.bottom=mRect.top+(int)(mViewHeight/mScale);

invalidate();
}
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
}

給view設置圖片

InputStream is=null;
try{
//加載圖片
is=getAssets().open("big.png");
bigView.setImage(is);
}catch(Exception e){
e.printStackTrace();
}finally {
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

上述代碼實現的是長圖加載的上下滑動,還有一種是巨圖的上下左右滑動,實現思路基本差不多,增加了x座標的計算,這裡就不介紹了。


分享到:


相關文章: