Have you seen the return of micro-channel sliding linkage effect, but the effect is to open the door, blinds effect seen it?

Android SmartSwipe is a sliding handle frame, which encapsulates the event of slip control ( up / down / left / right direction of the slide 4 gesture event capture), the multi-point distribution and replacement process slide, we can based SmartSwipe add a variety of controls you want to slip effect.

Let's look at what it can do it!

如果已经了解SmartSwipe的功能,只是想了解他的实现原理
可跳过第一节,直接看第二节的原理介绍

First, usage and presentation

1.1 line of code to achieve global sliding return

//仿手机QQ的手势滑动返回
SmartSwipeBack.activityStayBack(application, null);        
//仿微信带联动效果的透明侧滑返回
SmartSwipeBack.activitySlidingBack(application, null);    
//侧滑开门样式关闭activity
SmartSwipeBack.activityDoorBack(application, null);        
//侧滑百叶窗样式关闭activity
SmartSwipeBack.activityShuttersBack(application, null);    
//仿小米MIUI系统的贝塞尔曲线返回效果
SmartSwipeBack.activityBezierBack(application, null);

More use of sliding returned please stamp here

Renderings:

Sliding return effect

1.2 line of code to make the page move up

//为控件添加仿iOS的弹性留白效果:
//当纵向不能滚动(或滚动到顶/底)时,若继续拖动,则UI呈现弹性留白效果,释放后平滑恢复
SmartSwipe.wrap(view)
    .addConsumer(new SpaceConsumer())
    .enableVertical();

Renderings:

Elastic effect blank

1.3 elastic line of code to make the page

//为控件添加仿MIUI的弹性拉伸效果:
//当纵向不能滚动(或滚动到顶/底)时,若继续拖动,则UI呈现弹性拉伸效果,释放后平滑恢复
SmartSwipe.wrap(view)
    .addConsumer(new StretchConsumer())
    .enableVertical();

Renderings:

Elastic stretching effect

1.4-generation line of add drop-down to refresh

//xxxMode第二个参数为false,表示工作方向为纵向:下拉刷新&上拉加载更多
//如果第二个参数设置为true,则表示工作方向为横向:右拉刷新&左拉加载更多
SmartSwipeRefresh.drawerMode(view, false).setDataLoader(loader);
SmartSwipeRefresh.behindMode(view, false).setDataLoader(loader);
SmartSwipeRefresh.scaleMode(view, false).setDataLoader(loader);
SmartSwipeRefresh.translateMode(view, false).setDataLoader(loader);

Please use the drop-down refresh more poke here

style Renderings
drawerMode drawerMode
behindMode behindMode
scaleMode scaleMode
translateMode translateMode

Sliding menu line of code was added 1.5

SmartSwipe.wrap(view)
    //添加抽屉效果,其效果与DrawerLayout相似
    //  DrawerLayout只支持左右2个方向,而DrawerConsumer支持上下左右4个方向
    .addConsumer(new DrawerConsumer())    
    //设置横向(左右两侧)的抽屉为同一个view(常见的侧滑显示删除按钮的功能)
    .setHorizontalDrawerView(buttonsViewGroup) 
    .setScrimColor(0x2F000000) //设置遮罩的颜色
    .setShadowColor(0x80000000)    //设置边缘的阴影颜色
    ;

Renderings:

Sliding menu

1.6 having a line of code to add a menu slidably interlocking effect

SmartSwipe.wrap(view)
    .addConsumer(new SlidingConsumer())
    .setRelativeMoveFactor(0.3F) //联动系数
    .setHorizontalDrawerView(buttonsView)
    .setScrimColor(0x2F000000)
    ;

Renderings:

Linkage sliding menu

Cool Cover 1.7

SmartSwipe.wrap(coverView)
    .addConsumer(new ShuttersConsumer()) //百叶窗效果
    .setScrimColor(0xAF000000)
    .enableAllDirections()
    .addListener(new SimpleSwipeListener() {
        @Override
        public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
            //封面打开后自动隐藏或移除
            wrapper.setVisibility(View.GONE);
        }
    });

Renderings:

Blinds Cover

SmartSwipe.wrap(coverView)
    .addConsumer(new DoorConsumer()) //开门效果
    .setScrimColor(0xAF000000)
    .enableAllDirections()
    .addListener(new SimpleSwipeListener() {
        @Override
        public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
            //封面打开后自动隐藏或移除
            wrapper.setVisibility(View.GONE);
        }
    });

Renderings:

Cover open

More settings on the cover, please refer to: Demo

Second, the realization principle

2.1 First introduce ViewDragHelper

ViewDragHelper Android is officially supported library has a utility class. It can help us deal with drag and drop controls: create a custom ViewGroup, will be dragged control is added to this custom in ViewGroup, and drag to deal with ViewDragHelper control.

ViewDragHelper main role is to: intercept the parent container touch events to capture a child control drag to reposition it in the parent container by changing the left and top of this child controls, so as to achieve the drag effect.

In the official support library, the associated sliding drawer SlidingPaneLayout and DrawerLayout, and CoordinatorLayout layout related BottomSheetBehavior and SwipeDismissBehavior, can see ViewDragHelper figure.

但是,ViewDragHelper的名称也表明它就是用来处理拖拽的,拖拽的对象必须是一个子View,在拖拽的过程中需要改变子控件的left和top,对于一些没有子View被拖拽的侧滑效果(例如:MIUI系统的贝塞尔曲线侧滑返回效果、手机QQ的侧滑返回效果及MIUI官方app中的普遍使用了的弹性拉伸效果等等),却有点力有不逮。

2.2 借鉴ViewDragHelper实现侧滑处理

针对侧滑这个手势,我们能不能将它的概念抽象一下,到底侧滑指的是什么呢?

  • 狭义侧滑:从屏幕的某个边缘开始向着远离该边缘的方向滑动
  • 广义侧滑:手指在屏幕上按下之后向着某个方向滑动

我的理解是,广义侧滑包含狭义侧滑,只不过是触发区域是否在屏幕边缘的区别罢了。

既然侧滑手势能被明确地抽象出来,那么我们是否可以借鉴ViewDragHelper的事件拦截思路将它做这样的封装?

对被侧滑控件的touch事件进行拦截分析,确认是否将其捕获作为侧滑手势
然后计算好侧滑的实时位移(手指滑动的位移,而不是不依赖于View的left与top)
再通过策略模式(Strategy Pattern)使用不同的策略不断消费侧滑的位移来进行侧滑效果的UI呈现。

答案是肯定的!

2.3 SmartSwipe的实现原理

SmartSwipe在ViewDragHelper的基础上,将它对子View的捕获及移动处理改造成对父View自身触摸事件的定性(能否及是否捕获)、定向(捕获的事件所触发的侧滑方向)及定位(事件捕获之后在侧滑方向上移动的距离),并将侧滑距离交由SwipeConsumer来消费,SwipeConsumer根据侧滑距离的变化对控件布局进行相应的改变。

SmartSwipe的封装思路如下:

  • 用一个ViewGroup将需要处理侧滑事件的控件View包裹起来(被包裹起来的控件作为它的contentView
  • 可以为这个ViewGroup添加一些附属控件(如:滑动抽屉
  • This ViewGroup interception of touch events and touch event is converted to slip away for consumption SwipeConsumer
  • SwipeConsumer corresponding changes according to the change of the layout of the control sliding distance
  • (Through inheritance SwipeConsumer, different ways to change the layout of controls : for example, contentViewchange the position and subsidiary controls, zooming, transparency, etc. ), so as to achieve the effect of various sideslip.

Thus, the sliding gesture recognition events and sliding distance calculation work within a unified framework to complete, as to achieve a variety of different UI rendering according to slip away, it can easily be achieved through inheritance SwipeConsumer.

2.4 How to create custom SwipeConsumer?

To achieve a stretching effect of the elastic frame built imitation MIUI system applications Case

根据侧滑距离,对contentView进行缩放和平移,从而实现弹性拉伸效果

code show as below:

public class StretchConsumer extends SwipeConsumer {
    @Override
    public void onDetachFromWrapper() {
        super.onDetachFromWrapper();
        View contentView = mWrapper.getContentView();
        if (contentView != null) {
            contentView.setScaleX(1);
            contentView.setScaleY(1);
            contentView.setTranslationX(0);
            contentView.setTranslationY(0);
        }
    }

    @Override
    public void onDisplayDistanceChanged(int distanceXToDisplay, int distanceYToDisplay, int dx, int dy) {
        View contentView = mWrapper.getContentView();
        if (contentView != null) {
            if (distanceXToDisplay >= 0 && isLeftEnable() || distanceXToDisplay <= 0 && isRightEnable()) {
                contentView.setScaleX(1 + Math.abs((float) distanceXToDisplay) / mWidth);
                contentView.setTranslationX(distanceXToDisplay / 2F);
            }
            if (distanceYToDisplay >= 0 && isTopEnable() || distanceYToDisplay <= 0 && isBottomEnable()) {
                contentView.setScaleY(1 + Math.abs((float) distanceYToDisplay) / mHeight);
                contentView.setTranslationY(distanceYToDisplay / 2F);
            }
        }
    }
}

That's all the code to achieve the effect of elastic stretch, very simple, is not it?

Its use is equally simple:

SmartSwipe.wrap(view) //指定目标控件
    .addConsumer(new StretchConsumer()) //添加弹性拉伸效果
    .enableVertical(); //指定工作方向为:上、下2个方向

Let's look at how imitation mobile phone QQ sideslip return results achieved

手机QQ侧滑时UI没有任何变化
在手指释放时,根据滑动的方向和速率来决定是否finish当前Activity

code show as below:

public class StayConsumer extends SwipeConsumer {
    private int mMinVelocity = 1000;

    public StayConsumer() {
        //不能通过滑动距离判断是否需要打开
        setOpenDistance(Integer.MAX_VALUE)
                .setMaxSettleDuration(0); //打开时无需动画,时间置为0
    }

    @Override
    protected void onDisplayDistanceChanged(int distanceXToDisplay, int distanceYToDisplay, int dx, int dy) {
        //滑动时不需要对contentView做任何改变
    }

    @Override
    public void onSwipeReleased(float xVelocity, float yVelocity) {
        //在释放时,根据速率和方向来决定是否打开
        if (Math.abs(xVelocity) > Math.abs(yVelocity)) {
            if (mDirection == DIRECTION_LEFT && xVelocity >= mMinVelocity || (mDirection == DIRECTION_RIGHT && xVelocity <= -mMinVelocity)) {
                //置为打开状态
                mCurSwipeDistanceX = getSwipeOpenDistance();
                mProgress = 1;
            }
        } else {
            if (mDirection == DIRECTION_TOP && yVelocity >= mMinVelocity || (mDirection == DIRECTION_BOTTOM && yVelocity <= -mMinVelocity)) {
                //置为打开状态
                mCurSwipeDistanceY = getSwipeOpenDistance();
                mProgress = 1;
            }
        }
        super.onSwipeReleased(xVelocity, yVelocity);
    }

    public int getMinVelocity() {
        return mMinVelocity;
    }

    //支持使用者设置最低速率的阈值
    public StayConsumer setMinVelocity(int minVelocity) {
        if (minVelocity > 0) {
            this.mMinVelocity = minVelocity;
        }
        return this;
    }
}

It is also very simple!

Click here to create custom SwipeConsumer detailed steps

summary

This article describes the use of the process frame and sliding SmartSwipe implementation principle, and introduces a method to customize the effect of slip by two examples.

Just an example of the text is relatively simple sliding effect, as to achieve the effect of a complex sliding introduction, readers if necessary, I am going to write another article to introduce a separate, if necessary, please give me a shout!

In addition, Star an open source project it is best to encourage and support!

Guess you like

Origin yq.aliyun.com/articles/709566