理解這篇文章還需要矩陣的知識Matrix詳解
PhotoView的使用-全方向滑動瀏覽
一、分析
需求:實現界面全方向滑動瀏覽功能。
實現方式:使用第三方庫PhotoView
PhotoView簡介
https://github.com/chrisbanes/PhotoView
PhotoView是一個大佬貢獻的圖片預覽控件,主要的功能有:
- 圖片手勢縮放;
- 旋轉;
- 全方向平滑滾動;
- 在滑動父控件下能夠運行良好;(例如:ViewPager)
其實可以實現這些功能的輪子github上還有很多,比如還有
https://github.com/bm-x/PhotoView
ImageViewZoom
大家就看心情選擇好了,我瞅着我選的這個有幾k個小星星。
項目中要用到的功能以及實現
1、將自定義view轉化爲圖片設置給photoView,實驗全方向滾動;
2、監聽photoView的滾動事件;
二、PhotoView的使用
1、配置
在我們項目module build.gradle中配置
目前已經到2.3版本了,但是那個版本上做了androidx的遷移,我不想搞,所以後退了幾個版本
dependencies {
implementation 'com.github.chrisbanes:PhotoView:2.1.4'
}
2、在xml佈局中引用該控件
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="822dp"/>
3、在Activity中調用
//full_information_view是自定義的View,這句是把自定義View轉化爲bitmap
Bitmap bitmap = loadBitmapFromView(full_information_view);
//將圖片設置給photoView
photoView.setImageBitmap(bitmap);
//設置圖片在photoView中的顯示形式,包括是否進行縮放、等比縮放、縮放後展示位置等;
photoView.setScaleType(ImageView.ScaleType.CENTER);
//使用矩陣來控制視圖的變換
Matrix matrix = new Matrix();
//獲取photoView的矩陣
photoView.getDisplayMatrix(matrix);
//進行2倍縮放
matrix.postScale(2.0f, 2.0f);
//保存矩陣
photoView.setDisplayMatrix(matrix);
//再次獲取
photoView.getDisplayMatrix(matrix);
float[] floats = new float[9];
//獲取矩陣的數值
matrix.getValues(floats);
//進行平移
float offsetX = Math.abs(floats[2]);
float offsetY = Math.abs(floats[5]);
matrix.preTranslate(offsetX, offsetY);
//保存矩陣
photoView.setDisplayMatrix(matrix);
3.1、設置圖片在photoView中的顯示形式
photoView.setScaleType(ImageView.ScaleType.CENTER);
包括是否進行縮放、等比縮放、縮放後展示位置等;
輪子大佬提供了七種scaleType的屬性值;
不設置的話,默認屬性值爲FIT_CENTER。在該模式下,圖片會被等比縮放到能夠填充控件大小,並居中展示;
這部分模式的定義可以參考Android ImageView 的scaleType 屬性圖解
大佬是照着這個仿寫的,實現效果大差不差。只是不支持MATRIX,即矩陣模式。
而這裏,我需要實現的是,不使用縮放。大佬提供的模式中,只有ImageView.ScaleType.CENTER沒有縮放。但是這個模式下photoView會展示圖片的中心部分,而我並不需要。
我希望達到的效果如下所示:
黑線部分代表photoView,紅線部分代表Drawable。
我希望不使用縮放,photoView顯示Drawable右上部分。而超出部分,就可以通過滾動進入可視區域。
但是setScaleType之後,實際效果是。很明顯Drawable相對於photoView,左移了一塊。
所以我還要對drawable進行平移操作。
3.2、Drawable平移
獲取當前Drawable的矩陣數值,左移值爲負,取絕對值。矩陣前乘,右移回來。
photoView.getDisplayMatrix(matrix);
float[] floats = new float[9];
//獲取矩陣的數值
matrix.getValues(floats);
//進行平移
float offsetX = Math.abs(floats[2]);
float offsetY = Math.abs(floats[5]);
matrix.preTranslate(offsetX, offsetY);
//保存矩陣
photoView.setDisplayMatrix(matrix);
注意,這個地方一定要使用前乘,表示對當前矩陣做平移操作。
如果postTranslate,將會取得錯誤的結果。至於上面的縮放爲什麼可以用postScale,是因爲一開始的時候矩陣初始化爲默認狀態,初始矩陣無論前乘後乘都不影響結果;
4、設置監聽
photoView.setOnMatrixChangeListener(new OnMatrixChangedListener() {
@Override
public void onMatrixChanged(RectF rect) {
Matrix matrix = new Matrix();
photoView.getDisplayMatrix(matrix);
float[] floats = new float[9];
matrix.getValues(floats);
float scaleX = floats[0];
float scaleY = floats[4];
//獲取當前平移的距離
float offsetX = Math.abs(floats[2]);
float offsetY = Math.abs(floats[5]);
Log.i("rachel", "scaleX: " + scaleX + "scaleY: " + scaleY + " x: " + offsetX + " y: " + offsetY);
Drawable drawable = photoView.getDrawable();
final float viewWidth = getImageViewWidth(photoView);
final float viewHeight = getImageViewHeight(photoView);
final float drawableWidth = drawable.getIntrinsicWidth() * scaleX;
final float drawableHeight = drawable.getIntrinsicHeight() * scaleY;
//可以移動的最大水平距離,爲photoView和drawable寬度差值的絕對值
final float x=Math.abs(viewWidth - drawableWidth);
final float y=Math.abs(viewHeight - drawableHeight);
horizontalProgressBar.setProcess(offsetX / (x * 1f));
verticalProgressBar.setProcess(offsetY / (y * 1f));
}
});
如下圖所示,紅色實線爲drawable當前所在位置。photoview的位置保持不變(黑色實線),drawable相對於photoview移動,所能移動的最大水平距離,爲photoView和drawable寬度差值的絕對值,即下圖所示X部分。垂直移動距離同理。
三、代碼分析
相關API整理
事件監聽
/**
* Interface definition for a callback to be invoked when the photo is experiencing a drag event
*/
public interface OnViewDragListener {
/**
* Callback for when the photo is experiencing a drag event. This cannot be invoked when the
* user is scaling.
*
* @param dx The change of the coordinates in the x-direction
* @param dy The change of the coordinates in the y-direction
*/
void onDrag(float dx, float dy);
}