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

本文已授權微信公衆號:鴻洋(hongyangAndroid)原創首發

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

DragPhotoView項目地址https://github.com/githubwing/DragPhotoView

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

本期跟以往不一樣:

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

效果圖如下:

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

一分鐘使用方式:


修改你的 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項目地址https://github.com/githubwing/DragPhotoView

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章