編輯:Android編程入門
Android開發過程中,想必都使用過PhotoView來實現圖片展示的功能。在最新版的sdk(android-23)有了一個原生的photoView,並且代碼實現也很簡單,邏輯也很清晰。我們在實際的工作中,遇到的需求可能與這些photoview現有功能有些細微的差別,需要修改,或者重新開發。本文簡單介紹下android-23中photoview涉及到的相關技術,相信讀者看完後會發現,其實很簡單。以下為實現思路和步驟
通過自定義視圖,繼承View,為外界提過public接口方法來設置drawable,或者提供自定義屬性在layout文件中設置drawable。在onDraw方法中,將drawable畫到canvas上。
圖片首次顯示時,一般要居中全部顯示在屏幕內,並且至少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);
}
}
上面講到了兩個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
我們可以自己在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;
}
通過以上講解,可以看出只要我們熟悉了matrix、rect的相關用法,Photoviewer的實現技術其實很簡單。常見的fling、snap動畫效果,photoview中也有實現,讀者感興趣的話,可以查看源碼自行研究。
Android源碼筆記——Camera系統架構
Camera的架構與Android系統的整體架構保持一致,如下圖所示,本文主要從以下四個方面對其進行說明。 Framework:Camera.java Android
android系統架構
Android其本質就是在標准的Linux系統上增加了Java虛擬機Dalvik,並在Dalvik虛擬機上搭建了一個JAVA的application framework,
android開發-界面設計基本知識Ⅳ
上一章講述了Android界面開發中的Widget,Service,BroadcastReceiver基本知識點,本章以一個實際案例-後台音樂播放器解析各個知識點之間的關
java/android線程池詳解
一,簡述線程池:線程池是如何工作的:一系列任務出現後,根據自己的線程池安排任務進行。如圖: 線程池的好處:重用線程池中的線程,避免因為線程的創建和銷毀所帶來的性能開銷。能