这交互炸了 (四) : 一分钟让你拥有微信拖拽透明返回 PhotoView

本文同步自wing的地方酒馆javascript

《交互炸了》或许是一系列高端特效教程, 文中会介绍一些比较炫酷的特效,以及实现的思路。特效实现自己也许不会有太大的难度。难点在于实现的思路。一旦思路被打开,特效将很简单实现。php

DragPhotoView项目地址github.com/githubwing/…java

你们好,本期是交互炸了第四期~ 本期带来的效果是最新版微信朋友圈看图下拖的效果,没见过的赶忙去更新微信啦~~android

本期跟以往不同:

不是demo! 拿来直接用!不是demo! 拿来直接用!不是demo! 拿来直接用!重要说三你懂.

效果图以下:git

自我感受实现的效果还不错哈.猛地一看本身都觉得他就是微信了哈哈.github

一分钟使用方式:


修改你的 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,这是在拖拽出范围的监听.canvas

// 全部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的支持.maven

图片缩放,背景透明

这里须要Activity配合,将背景设置为透明.而且背景实黑色的,为了配合手势改变View背景透明度,我绘制一个超大的矩形充当背景:ide

@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变成详情页的

第二期:这交互炸了 (二):爱范儿是如何让详情页缩小为横向列表的

第三期:这交互炸了(三) :不看后悔!你必定没见过这样的闪屏

相关文章
相关标签/搜索