這互動炸了 (四) : 一分鐘讓你擁有微信拖拽透明返回 PhotoView

androidwing發表於2016-12-25

本文同步自wing的地方酒館

《互動炸了》或許是一系列高階特效教程, 文中會介紹一些比較炫酷的特效,以及實現的思路。特效實現本身也許不會有太大的難度。難點在於實現的思路。一旦思路被開啟,特效將很簡單實現。

DragPhotoView專案地址github.com/githubwing/…

大家好,本期是互動炸了第四期~ 本期帶來的效果是最新版微信朋友圈看圖下拖的效果,沒見過的趕緊去更新微信啦~~

本期跟以往不一樣:

不是demo! 拿來直接用!不是demo! 拿來直接用!不是demo! 拿來直接用!重要說三你懂.

效果圖如下:

這互動炸了 (四) : 一分鐘讓你擁有微信拖拽透明返回 PhotoView

自我感覺實現的效果還不錯哈.猛地一看自己都以為他就是微信了哈哈.

一分鐘使用方式:


修改你的 build.gradle檔案


//root project
allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

//module project
        dependencies {
            compile 'com.github.githubwing:DragPhotoView:1.0.1'
    }複製程式碼

把它放到xml裡

把它當成普通ImageView使用就行了,所有ImageView的玩法都可以在它身上玩.注意必須要加一個onExitListener,這是在拖拽出範圍的監聽.


    // 所有ImageView用法都可以    
    DragPhotoView photoView = (DragPhotoView)findViewById(R.id.photoView);
    photoView.setImageResource(R.drawable.ram);
    //必須新增一個onExitListener,在拖拽到底部時觸發.    
    photoView.setOnExitListener()

    photoView.setOnTapListener()複製程式碼

這樣就完成了接入,甚至比一分鐘還快有沒有!拒絕標題黨.


上面講解的是用法,可是用誰都會,使用一個三方庫,都要了解實現對不? 下面就給大家介紹實現的思路.

實現

基於PhotoView

第一眼看到這個效果,就有想實現的衝動,因為使用場景挺多的感覺. 所以直接找來GitHub上star最多的PhotoView來進行擴充套件,這裡我選擇直接依賴並且繼承PhotoView,理由是如果PhotoView出了更新,依賴直接改動版本即可.如果我選擇原始碼copy的方式改動,那麼將得不到PhotoView的支援.

圖片縮放,背景透明

這裡需要Activity配合,將背景設定為透明.並且背景實黑色的,為了配合手勢改變View背景透明度,我繪製一個超大的矩形充當背景:

  @Override
    protected void onDraw(Canvas canvas) {
        mPaint.setAlpha(mAlpha);
        canvas.drawRect(0, 0, 2000, 2000, mPaint);
        canvas.translate(mTranslateX, mTranslateY);
        canvas.scale(mScale, mScale, mWidth / 2, mHeight / 2);
        super.onDraw(canvas);
    }複製程式碼

畫布位移和縮放還有透明度都跟著手勢變化而變化.所以要處理觸控事件,一開始我嘗試重寫onTouchEvent方法,發現並不生效,原因是PhotoView內部使用了自己的手勢處理機制. 所以手勢處理束手無策裡嗎? 非也,我們可以在dispatchTouchEvent做處理.所以重寫該方法:

首先判斷是否處於縮放模式,只有非縮放模式的時候才可以拖拽


    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (getScale() == 1) {
        }
    }複製程式碼

之後處理ACTION_MOVE事件:
需要注意的是,要解決一下Viewpager和DragPhotoView和PhotoView的衝突.

DragPhotoView和PhotoView的衝突在於手勢縮放,所以只要判斷一下當前是幾個觸控點即可.

下Viewpager和DragPhotoView衝突在左右滑,所以這裡判斷為:如果沒有向下移動過,則Y位移為0交由ViewPager處理,如果向下移動過,則改變標誌位說明正在處於拖拽狀態

     case MotionEvent.ACTION_MOVE:

                    //in viewpager
                    if (mTranslateY == 0 && mTranslateX != 0) {

                        //如果不消費事件,則不作操作
                        if (!isTouchEvent) {
                            mScale = 1;
                            return super.dispatchTouchEvent(event);
                        }
                    }

                    //single finger drag  down
                    if (mTranslateY >= 0 && event.getPointerCount() == 1) {
                        onActionMove(event);

                        //如果有上下位移 則不交給viewpager
                        if (mTranslateY != 0) {
                            isTouchEvent = true;
                        }
                        return true;
                    }


                    //防止下拉的時候雙手縮放
                    if (mTranslateY >= 0 && mScale < 0.95) {
                        return true;
                    }
                    break;複製程式碼

在ACTION_UP的時候,要判斷一下是否拖拽超過閥值,如果超過了閥值則進行結束Activity操作.

這裡遇到個坑就是,單指返回和雙擊放大手勢衝突了.目前沒有找到什麼好的解決方法,只能開啟執行緒計時來根據標誌位判斷,各位看官有好的解決方式,請聯絡告知我,謝謝!

case MotionEvent.ACTION_UP:
                    //防止下拉的時候雙手縮放
                    if (event.getPointerCount() == 1) {
                        onActionUp(event);
                        isTouchEvent = false;
                        //judge finish or not
                        postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                if (mTranslateX == 0 && mTranslateY == 0 && canFinish) {

                                    if (mTapListener != null) {
                                        mTapListener.onTap(DragPhotoView.this);
                                    }
                                }
                                canFinish = false;
                            }
                        }, 300);
                    }複製程式碼

這樣基本上就完成了對PhotoView的擴充套件. 已經可以接入專案中使用了.

但是本文還沒有完,下面說一下共享元素的全版本實現

Android自帶的共享元素只有5.0以上才可以使用.那麼怎麼相容到5.0以下呢.並且Demo中的拖拽共享是怎麼實現的呢?

其實思路很簡單,只需要在Activity A啟動Activity B的時候,關閉系統專場動畫,把被點選的View 大小,座標等資訊傳入. B先為透明狀態,把B上的View做一個位移動畫,就可以實現了.

 public  void startPhotoActivity(Context context, ImageView imageView) {
    Intent intent = new Intent(context, DragPhotoActivity.class);
    int location[] = new int[2];

    imageView.getLocationOnScreen(location);
    intent.putExtra("left", location[0]);
    intent.putExtra("top", location[1]);
    intent.putExtra("height", imageView.getHeight());
    intent.putExtra("width", imageView.getWidth());

    context.startActivity(intent);

    //關閉系統共享元素動畫
    overridePendingTransition(0,0);
  }複製程式碼

至於拖拽共享元素,原理是一樣的,具體的細節就在demo中啦~~

本文到此就結束啦~

DragPhotoView專案地址github.com/githubwing/…

如果你覺得不錯,歡迎Star,也可以加入我的Android酒館:425983695

擴充套件閱讀

第一期:這互動炸了:餓了麼是怎麼讓Image變成詳情頁的

第二期:這互動炸了 (二):愛範兒是如何讓詳情頁縮小為橫向列表的

第三期:這互動炸了(三) :不看後悔!你一定沒見過這樣的閃屏

相關文章