最近在實(shí)現(xiàn)一個(gè)類似淘寶中的評(píng)論列表的功能,其中要在列表中顯示評(píng)論圖,點(diǎn)擊圖片后顯示大圖進(jìn)行查看,各家app幾乎都會(huì)有這樣的功能。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

可以看到,一個(gè)體驗(yàn)較好的查看大圖的基本功能有,

第一,左右滑動(dòng)時(shí)切換圖片;

第二,雙擊或雙指縮放實(shí)現(xiàn)圖片的縮放;

第三,圖片放大時(shí),滑動(dòng)到邊緣繼續(xù)滑動(dòng)時(shí),切換圖片。

因?yàn)槲覀兊腶pp中使用了fresco庫(kù),但fresco提供的SimpleDraweeView不支持縮放,看網(wǎng)上有人擴(kuò)展了SimpleDraweeView,使之支持縮放。但經(jīng)過(guò)漫長(zhǎng)的調(diào)研,發(fā)現(xiàn)fresco近期提供了一個(gè)新的sample:ZoomableDraweeView,專門(mén)用來(lái)支持縮放,欣喜若狂的下載下來(lái)把玩了一把,發(fā)現(xiàn)三個(gè)需求點(diǎn)都滿足!可惜的是,這個(gè)控件在細(xì)節(jié)上有幾點(diǎn)不滿足:雙擊后放大到最大,再雙擊后卻縮小為最小(期望恢復(fù)為正常大?。?,雖然最小可以設(shè)置,但這個(gè)值應(yīng)該是在雙指縮小時(shí)才用到。另一點(diǎn)是在雙指縮小并松開(kāi)后,圖片保持在那個(gè)縮小的尺寸(期望自動(dòng)恢復(fù)為正常大?。?/p>

查看代碼后發(fā)現(xiàn)需要修改幾點(diǎn)就可以滿足我的需求。下面的內(nèi)容主要記錄我思考問(wèn)題、解決問(wèn)題的思路,如果你也有類似的需求,可以直接拿代碼:https://github.com/ibosong/CommentGallery

1. 雙擊恢復(fù)正常尺寸

修改DoubleTapGestureListener 中的onDoubleTapEvent方法,因?yàn)橹饕薷牡倪壿嬙陔p指松開(kāi)后,于是我們?cè)贛otionEvent.ACTION_UP的case中修改相關(guān)邏輯。首先判斷mDoubleTapScroll,即是否是雙擊后不松開(kāi)并滑動(dòng)的操作,這種操作下如果在松開(kāi)手指時(shí),圖片為縮小狀態(tài),應(yīng)當(dāng)恢復(fù)正常大小,所以將原代碼:

if (mDoubleTapScroll) {  float scale = calcScale(vp);
  zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
}

修改為:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

if (mDoubleTapScroll) {    float scale = calcScale(vp);    if (scale < 1.0f) {
        zc.zoomToPoint(1.0f, mDoubleTapImagePoint, mDoubleTapViewPoint,
                DefaultZoomableController.LIMIT_ALL,
                DURATION_MS,                null);
    } else {
        zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

else里面的代碼是正常雙擊后的代碼,將其中的minScale 改為1.0f即可

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

else {    final float maxScale = zc.getMaxScaleFactor();    final float minScale = zc.getMinScaleFactor();    if (zc.getScaleFactor() < (maxScale + minScale) / 2) {
        zc.zoomToPoint(
                maxScale,
                ip,
                vp,
                DefaultZoomableController.LIMIT_ALL,
                DURATION_MS,                null);

    } else {
        zc.zoomToPoint(                /*minScale*/1.0f,
                ip,
                vp,
                DefaultZoomableController.LIMIT_ALL,
                DURATION_MS,                null);
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

2. 雙指縮放,處理雙指縮小圖片后松開(kāi)手指的情況

閱讀代碼可知,ZoomableDraweeView中的onTouchEvent方法調(diào)用了DefaultZoomableController的onTouchEvent方法,這里面通過(guò)mGestureDetector的處理,最終回調(diào)到ZoomableDraweeView中的onGestureBegin,onGestureUpdate和onGestureEnd這三個(gè)方法中。mGestureDetector的處理是在MultiPointerGestureDetector的onTouchEvent方法中。這里面原來(lái)的按下和松開(kāi)手指的邏輯是這樣的:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

= (mPointerCount > 0 &&

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

每次在MotionEvent.ACTION_DOWN和MotionEvent.ACTION_UP情況下執(zhí)行相同的動(dòng)作:先stopGesture,然后startGesture,即先觸發(fā)onGestureEnd,然后觸發(fā)onGestureBegin。顯然這樣的處理是不合邏輯的,為什么在手指按下的時(shí)候要觸發(fā)onGestureEnd?于是我們將代碼修改為:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

= (mPointerCount > 0 &&=

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

在手指按下的時(shí)候觸發(fā)onGestureBegin,手指抬起的時(shí)候觸發(fā)onGestureEnd。這時(shí)候我們只要在DefaultZoomableController中的onGestureEnd方法中處理松開(kāi)手指的情況:如果圖片被縮小,則通過(guò)調(diào)用zoomToPoint方法將圖片恢復(fù)正常大小。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

@Overridepublic void onGestureEnd(TransformGestureDetector detector) {
    FLog.v(TAG, "onGestureEnd");    // When the image was zoomed in, releasing the fingers will restore the size of image.
    if (getScaleFactor() < 1.0f) {
        zoomToPoint(1.0f, new PointF(0.f, 0.f), new PointF(0.f, 0.f));
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

這里onGestureUpdate方法里的邏輯也要改一下,不要再調(diào)用mGestureDetector.restartGesture()。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

 "onGestureUpdate" transformCorrected ==

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

這樣實(shí)現(xiàn),操作起來(lái)比較生硬,恢復(fù)大小的時(shí)候沒(méi)有動(dòng)畫(huà)。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

于是我們將onGestureEnd中的處理移至AbstractAnimatedZoomableController中,并將zoomToPoint修改為另一個(gè)實(shí)現(xiàn)了動(dòng)畫(huà)的重載的方法:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

@Overridepublic void onGestureEnd(TransformGestureDetector detector) {    // When the image was zoomed in, releasing the fingers will restore the size of image.
    if (getScaleFactor() < 1.0f) {
        zoomToPoint(1.0f, new PointF(0.f, 0.f), new PointF(0.f, 0.f), LIMIT_ALL, 300, null);
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

這樣我們的改造就全部完成了,安裝體驗(yàn)一下。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)