Android加載長圖滑動顯示

1、記錄下學到的Android加載長圖寫法以備後用

首先準備一張長圖。這裏把圖片先放到項目的 assets文件夾下:命名爲big.png

然後開始自定義顯示長圖的view :BigView

 
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.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 Scroller mScroller;
    private Rect mRect;
    private BitmapFactory.Options mOptions;
    private GestureDetector mGresureDetector;
    private int mImageWight,mImageHeight;
    private BitmapRegionDecoder mDecoder;
    private int mViewWidth,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();
        //手勢識別類
        mGresureDetector = new GestureDetector(context,this);
        //設置onTouchListener
        setOnTouchListener(this);
        //滑動幫助
        mScroller = new Scroller(context);
    }
 
    /**
     * 由使用者輸入一張圖片
     * @param is
     * @return
     */
    public void setImage(InputStream is){
        //先讀取原圖片的信息  寬、高
        mOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is,null,mOptions);
        mImageWight = mOptions.outWidth;
        mImageHeight = mOptions.outHeight;
 
        //開啓複用
        mOptions.inMutable = true;
        //設置格式成RBG_565,因爲565 存儲像素點佔用內存小,一個像素點只需要兩個字節
        mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
 
        mOptions.inJustDecodeBounds = false;
 
        //創建一個區域解碼器
        try {
            mDecoder = BitmapRegionDecoder.newInstance(is,false);
 
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        requestLayout();
    }
 
    /**
     * 在測量的時候把我們需要的內存區域獲取到  存入到mRect中
     * @param
     * @return
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //獲取測量的view的大小
        mViewWidth = getMeasuredWidth();
        mViewHeight = getMeasuredHeight();
        //如果解碼器拿不到,表示沒有設置過要顯示的圖片
        if (null == mDecoder){
            return;
        }
        //確定要加載的圖片的區域
        mRect.left = 0;
        mRect.top = 0;
        mRect.right = mImageWight;
        //獲取一個縮放比例
        mScale = mViewWidth / (float)mImageWight;
 
        //高度就根據縮放比進行獲取
        mRect.bottom = (int)(mViewHeight/mScale);
 
    }
 
    /**
     * 畫出內容
     * @param
     * @return
     */
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        //如果解碼器拿不到,表示沒有設置過要顯示的圖片
        if (null == mDecoder){
            return;
        }
        //複用上一張bitmao
        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;
    }
 
    /**
     *
     * @param e1 手勢按下去的事件   開始獲取座標
     * @param e2 當前手勢事件   獲取當前座標
     * @param distanceX  x方向移動的距離
     * @param distanceY  y方向移動的距離
     * @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) {
 
        //做計算  -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) {
 
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //交給手勢處理
        return mGresureDetector.onTouchEvent(event);
    }
}

自定義view寫完後,在要顯示的佈局中引入這個bigview控件,這個就不寫了,放到佈局就行了

下面在activity中展示:

public class BigViewActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.bigview_layout);
 
        BigView bigView = findViewById(R.id.bigview);
        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();
                }
            }
        }
    }
}

好了這些就行了,運行就可以看到加載長圖,手動上下滑動瀏覽大圖了

轉自:文藝範的世界 

原文鏈接:原文鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章