Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android編程入門 >> Android PhotoView基本功能實現

Android PhotoView基本功能實現

編輯:Android編程入門

Android開發過程中,想必都使用過PhotoView來實現圖片展示的功能。在最新版的sdk(android-23)有了一個原生的photoView,並且代碼實現也很簡單,邏輯也很清晰。我們在實際的工作中,遇到的需求可能與這些photoview現有功能有些細微的差別,需要修改,或者重新開發。本文簡單介紹下android-23中photoview涉及到的相關技術,相信讀者看完後會發現,其實很簡單。以下為實現思路和步驟

  • 1 自定義一個View

通過自定義視圖,繼承View,為外界提過public接口方法來設置drawable,或者提供自定義屬性在layout文件中設置drawable。在onDraw方法中,將drawable畫到canvas上。

  • 2 首次顯示drawable

圖片首次顯示時,一般要居中全部顯示在屏幕內,並且至少x軸或y軸方向占滿屏幕。如何實現?

對於一個drawable,可以獲取其原始的寬、高:

int drawableWidth = mDrawable.getIntrinsicWidth();
int drawableHeight = mDrawable.getIntrinsicHeight();

然後將原始的寬、高,保存到一個RectF對象中:

private RectF mTmpRectSrc = new Rect(); 
mTmpRectSrc.set(0, 0, drawableWidth, drawableHeight);

自定義的視圖在measure完之後,會有一個寬、高:

int viewWidth = getWidth();
int viewHeight = getHeight();

將view的寬、高也保存到一個RectF對象中:

private RectF mTmpRectDst = new RectF();
mTmpRectDst.set(0, 0, viewWidth, viewHeight);

這時候,可以計算出一個從 mTmpRectSrc 到 mTmpRectDst的變換矩陣:

private Matrix mDrawMatrix = new Matrix();
mDrawMatrix.setRectToRect(mTmpRectSrc, mTmpRectDst, Matrix.ScaleToFit.CENTER);

Matrix.scaleToFit.CENTER參數確保圖片最後可以:居中全部顯示在屏幕內,並且至少x軸或y軸方向占滿屏幕。

最後,在onDraw方法中,結合上面到到的mDrawMatrix,即可將drawable畫到canvas上:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawable != null) {
int saveCount = canvas.getSaveCount();
canvas.save();
canvas.concat(mDrawMatrix);
mDrawable.draw(canvas);
canvas.restoreToCount(saveCount);
}
}
  • 3 如何獲取drawable的實現顯示區域

上面講到了兩個RectF區域,和一個matrix。分別是:

mTmpRectSrc: drawable原始矩形區域

ScaleGestureDetector
GestureDetector

 

mTmpRectDst: view顯示矩形區域

mDrawMatrix: 從mTmpRectSrc到mTmpRectDst的變換矩陣

 

如何的到矩陣變換後,圖片的實際顯示區域?這裡要注意,mTmpRectDst並非圖片的顯示區域,這個矩形區域僅僅是用來限定圖片的顯示區域,而最終的顯示區域並不是他。方法很簡單:

private RectF mTranslateRect = new Rect();
mDrawMatrix.mapRect(mTranslateRect, mTmpRectSrc);

然後通過mTranslateRect,就可以獲取最終顯示圖片矩形區域的letf/top/right/bottom

  • 4 識別縮放手勢和滑動手勢

我們可以自己在onTouchEvent方法中識別出滑動、縮放等手勢。但朋友們是否有感覺,這些判斷邏輯自己實現起來很繁瑣,很難保證邏輯的完美無缺。其實android系統提供了兩個很好用的輔助類來幫我們做這些事情:

GestureDetector
ScaleGestureDetector

GestureDetector可以用來識別滑動(scroll),ScaleGestureDetector可以用來識別縮放(scale)

我們來看看如何處理scroll。

首先定一個GestureDetector:

mGestureDetector = new GestureDetector(context, this);

this是指GestureDetector.OnGestureListener的實現類,這裡可以用view自己來實現。實現的onScroll方法如下:

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    mDrawMatrix.mapRect(mTranslateRect, mTmpRectSrc);
    distanceX = -distanceX;
    distanceY = -distanceY;
    mDrawMatrix.postTranslate(distanceX, distanceY);
    invalidate();
    return true;
}

直接將接口傳給我們的x,y方向偏移量設置到matrix中,然後invalidate,view重新draw出來的drawable就移動了。實際應用中,我們可以先獲取drawable的實際顯示矩形區域,再根據x,y方向偏移量,計算得出最後的偏移量,來限制不可以將圖片劃出view顯示區域。

 

還差一步,需要在view的onTouchEvent方法中,將MotionEvent事件傳給GestureDetector,這樣就可以用手指來移動圖片了:

@Override
public boolean onTouchEvent(MotionEvent event) {
    mGestureDetector.onTouchEvent(event);
    return true;
}

如果少了這步,GestureDetector根據接觸不到MotionEvent,也就無法幫我們識別相關手勢。

 

處理縮放幾本一樣,首先定義detector:

private ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(context, this);

this是ScaleGestureDetector.OnScaleGestureListener的實現類,這裡可以用view自己來實現。實現的方法為:

@Override
public boolean onScale(ScaleGestureDetector detector) {
    float factor = detector.getScaleFactor();

    mDrawMatrix.mapRect(mTranslateRect, mTmpRectSrc);

    int width = getWidth();
    float centerX;
    if (factor > 1 && mTranslateRect.right - mTranslateRect.left < width) {
        centerX = mTranslateRect.left * width / (mTranslateRect.left + width - mTranslateRect.right);
    } else {
        centerX = detector.getFocusX();
    }

    int height = getHeight();
    float centerY;
    if (factor > 1 && mTranslateRect.bottom - mTranslateRect.top < height) {
        centerY = mTranslateRect.top * height / (mTranslateRect.top + height - mTranslateRect.bottom);
    } else {
        centerY = detector.getFocusY();
    }
    mDrawMatrix.postScale(factor, factor, centerX, centerY);
    invalidate();
    return true;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
    return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}

首先,onScaleBegin方法要返回true,否則不會回調onScale。在onScale中,可以獲取縮放中心點、縮放比例,以及當前圖片的實際顯示區域,根據實際需求,計算出一個最終的縮放比例、中心點。最後將結果postScale到matrix中,invalidate,view重新draw之後,就可看到縮放的效果

 

最後,需要在view的onTouchEvent方法中,將觸摸時間告知scaleDetector。否則,scaleDetector根本接觸不到相關事件,不會回調相關方法:

@Override
public boolean onTouchEvent(MotionEvent event) {
    mScaleGestureDetector.onTouchEvent(event);
    mGestureDetector.onTouchEvent(event);
    return true;
}

 

  • 5 總結

通過以上講解,可以看出只要我們熟悉了matrix、rect的相關用法,Photoviewer的實現技術其實很簡單。常見的fling、snap動畫效果,photoview中也有實現,讀者感興趣的話,可以查看源碼自行研究。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved