最近打算學習一下圖片相關的處理知識,首先學習縮放顯示,而這個控件是我了解到比較好的,果斷學習之。
源碼版本是:2.1.3
dependencies {
compile 'com.github.chrisbanes:PhotoView:2.1.3'
}
對于如何使用,這里就不再贅述了,可以參考官方文檔。
簡介
首先上一張代碼結構圖,解釋一下各個類大概都做了些什么。

稍微有點模糊,但是能看清,類的數(shù)量不多,接口就占了一大半,其中核心的類其實就三個,解釋如下:
PhotoView 正如官方文檔說的一樣,可完全替換掉之前代碼中的ImageView,還可以設置一系列監(jiān)聽回調(diào)和一些屬性的控制,例如是否支持縮放,圖片旋轉(zhuǎn)角度等
PhotoViewAttacher 這個是這個框架的核心類,PhotoView中設置的信息都是通過這個Attacher去處理的,當然各種手勢操作的流程和協(xié)調(diào)也是在這個類中處理
CustomGestureDetector 這個類其實是集成縮放和拖動手勢的邏輯,處理完后再回調(diào)到OnGestureListener接口中去處理相應的操作(onDrag,onFling,onScale)
還有一個重要的技術點就是,所有的操作都是通過使用Matrix實現(xiàn),而為了實現(xiàn)這個功能,巧妙的使用三個Matrix來實現(xiàn):
mBaseMatrix 在圖片設置成功后,會初始化的一個基礎Matrix,是根據(jù)圖片的ScaleType,對原圖片進行的scale和translation操作后得到的Matrix
mSuppMatrix 這個是圖片經(jīng)過手勢操作,變換的scale和translation
mDrawMatrix 這個是最終設置給PhotoView的Matrix,三者的關系是:
mDrawMatrix = mSuppMatrix * mBaseMatrix
這樣一來,把手勢操作的變化的Matrix和原本的Matrix完美的分開了,互不影響,又能實現(xiàn)最終樣式,想想都覺得贊。
對于Matrix的學習,其實先理解一下矩陣的乘法就容易很多了,而系統(tǒng)也封裝好了對于scale和translation的方法,當然也還有rotate,具體的用法這里也不介紹了,可自行Google。
事件流程圖

簡單解釋一下我理解到的流程:
1、首先PhotoView初始化,會創(chuàng)建一個全局變量PhotoViewAttacher,PhotoView中的方法基本都是通過調(diào)用該mAttacher來實現(xiàn)的;
2、創(chuàng)建PhotoViewAttacher時,attacher會初始化一個OnTouchListener和OnLayoutChangeListener,前者是為了得到各種事件,便于處理,后者是為了讓設置圖片成功后,通知attacher去初始化mBaseMatrix;
3、接著也會初始化兩個手勢:mScaleDragDetector和mGestureDetector,兩者都需要調(diào)用其onTouchEvent方法,先說后一個,對于GestureDetector,是系統(tǒng)提供的手勢操作,這里回調(diào)了雙擊,單擊,長按以及滑動,通過回調(diào)的雙擊支持雙擊放大和縮小,而其他的只是提供一個回調(diào)。
4、再來看mScaleDragDetector,這個是自定義的一個類,用來實現(xiàn)縮放和滑動的,初始化時傳入了OnGestureListener,用于回調(diào)到相應操作,包含了onDrag、onFling、onScale;縮放是通過系統(tǒng)的ScaleGestureDetector手勢實現(xiàn),同樣調(diào)用其onTouchEvent方法,即可回調(diào)到OnScaleGestureListener中,再回調(diào)給OnGestureListener的onScale方法;滑動是處理onTouchEvent,處理ACTION_DOWN,ACTION_MOVE,ACTION_UP事件,都是常規(guī)操作就不詳細解釋了。在ACTION_MOVE中回調(diào)了onDrag,在ACTION_UP時回調(diào)了onFling,對于fling滑動使用了一個OverScroller去執(zhí)行彈性滑動;對于滑動使用的是matrix的postTranslate方法,縮放使用的是matrix的postScale,當然這個matrix是上文中說的mSuppMatrix。
5、最后在OnGestureListener的三個方法中通過使用mSuppMatrix實現(xiàn)圖片的滑動和縮放,再調(diào)用setImageMatrix,給圖片設置上mDrawMatrix就得到了最終的效果。
6、對于事件分發(fā)問題,先是在onTouch中通過requestDisallowInterceptTouchEvent得到事件,讓父容器不攔截事件,再在onDrag中通過requestDisallowInterceptTouchEvent,根據(jù)判斷條件是否讓父容器來攔截之后的事件,從而解決事件分發(fā)問題。
至此就分析就基本分析完了,對于事件分發(fā)以及事件處理、手勢處理以及圖片對的Matrix都有了新的收獲和認識,果然閱讀好的源碼是一件值得去做的事。