Android-PhotoView的使用-全方向滑動瀏覽

PhotoView的使用

理解這篇文章還需要矩陣的知識Matrix詳解

一、分析

需求:實現界面全方向滑動瀏覽功能。
實現方式:使用第三方庫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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章