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

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

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

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

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

本期跟以往不同:

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

效果圖以下:微信

自我感受實現的效果還不錯哈.猛地一看本身都覺得他就是微信了哈哈.markdown

一分鐘使用方式:


修改你的 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,這是在拖拽出範圍的監聽.maven

// 全部ImageView用法均可以 
    DragPhotoView photoView = (DragPhotoView)findViewById(R.id.photoView);
    photoView.setImageResource(R.drawable.ram);
    //必須添加一個onExitListener,在拖拽到底部時觸發.   
    photoView.setOnExitListener()

    photoView.setOnTapListener()

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


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

實現

基於PhotoView

第一眼看到這個效果,就有想實現的衝動,由於使用場景挺多的感受. 因此直接找來GitHub上star最多的PhotoView來進行擴展,這裏我選擇直接依賴而且繼承PhotoView,理由是若是PhotoView出了更新,依賴直接改動版本便可.若是我選擇源碼copy的方式改動,那麼將得不到PhotoView的支持.post

圖片縮放,背景透明

這裏須要Activity配合,將背景設置爲透明.而且背景實黑色的,爲了配合手勢改變View背景透明度,我繪製一個超大的矩形充當背景:gradle

@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

相關文章
相關標籤/搜索