侧滑效果[第十二篇]:侧滑框架SmartSwipe之仿微信返回效果

首先看下效果:

294.gif

这个效果的Activity返回效果和微信很相似。

SmartSwipe框架中实现仿微信返回效果的类是ActivitySlidingBackConsumer,代码如下:

/**
 * swipe to finish activity. make current activity translucent to show the previous activity
 * thanks:
 *  1. https://github.com/ikew0ng/SwipeBackLayout
 *  2. https://github.com/Simon-Leeeeeeeee/SLWidget
 * @author billy.qi
 */
public class ActivitySlidingBackConsumer extends TranslucentSlidingConsumer {

    protected final ActivityTranslucentUtil mActivityTranslucentUtil;
    protected Activity mActivity;
    protected int initTranslation = 0;
    protected View mPreviousActivityContentView;
    protected boolean mHorizontalSwiping;

    public ActivitySlidingBackConsumer(Activity activity) {
        this.mActivity = activity;
        this.mActivityTranslucentUtil = new ActivityTranslucentUtil(activity);
        showScrimAndShadowOutsideContentView();
        //set default shadow color and shadow size
        setShadowColor(0x80000000);
        setShadowSize(SmartSwipe.dp2px(10, activity));
    }

    @Override
    public boolean tryAcceptMoving(int pointerId, float downX, float downY, float dx, float dy) {
        return super.tryAcceptMoving(pointerId, downX, downY, dx, dy);
    }

    @Override
    public boolean tryAcceptSettling(int pointerId, float downX, float downY) {
        return false;
    }

    @Override
    public void onAttachToWrapper(SmartSwipeWrapper wrapper, SwipeHelper swipeHelper) {
        super.onAttachToWrapper(wrapper, swipeHelper);
        ActivityTranslucentUtil.convertWindowToTranslucent(mActivity);
    }

    @Override
    public void onDetachFromWrapper() {
        super.onDetachFromWrapper();
        mActivityTranslucentUtil.convertActivityFromTranslucent();
        resetPreviousActivityContentView();
    }

    @Override
    protected void onOpened() {
        super.onOpened();
        if (mListeners == null || mListeners.isEmpty()) {
            if (mActivity != null) {
                mActivity.finish();
                mActivity.overridePendingTransition(R.anim.anim_none, R.anim.anim_none);
            }
        }
        resetPreviousActivityContentView();
    }

    @Override
    protected void onClosed() {
        super.onClosed();
        mActivityTranslucentUtil.convertActivityFromTranslucent();
        resetPreviousActivityContentView();
    }

    private void resetPreviousActivityContentView() {
        if (mPreviousActivityContentView != null) {
            mPreviousActivityContentView.setTranslationX(0);
            mPreviousActivityContentView.setTranslationY(0);
            mPreviousActivityContentView = null;
        }
    }

    @Override
    protected void initChildrenFormXml() {
        //do nothing
    }

    @Override
    public void onSwipeAccepted(int activePointerId, boolean settling, float initialMotionX, float initialMotionY) {
        if (!mActivityTranslucentUtil.isTranslucent()) {
            mActivityTranslucentUtil.convertActivityToTranslucent();
        }
        if (mRelativeMoveFactor > 0) {
            mHorizontalSwiping = (mDirection & DIRECTION_HORIZONTAL) > 0;
            Activity previousActivity = SmartSwipeBack.findPreviousActivity(mActivity);
            if (previousActivity != null) {
                mPreviousActivityContentView = previousActivity.getWindow().getDecorView();
                switch (mDirection) {
                    case DIRECTION_LEFT:    initTranslation = -(int) (mWidth * mRelativeMoveFactor); break;
                    case DIRECTION_RIGHT:   initTranslation = (int) (mWidth * mRelativeMoveFactor); break;
                    case DIRECTION_TOP:     initTranslation = -(int) (mHeight * mRelativeMoveFactor); break;
                    case DIRECTION_BOTTOM:  initTranslation = (int) (mHeight * mRelativeMoveFactor); break;
                    default:
                }
                movePreviousActivityContentView(initTranslation);
            }
        }
        super.onSwipeAccepted(activePointerId, settling, initialMotionX, initialMotionY);
    }

    private void movePreviousActivityContentView(int translation) {
        if (mPreviousActivityContentView == null || !mActivityTranslucentUtil.isTranslucent()) {
            return;
        }
        if (mHorizontalSwiping) {
            mPreviousActivityContentView.setTranslationX(translation);
        } else {
            mPreviousActivityContentView.setTranslationY(translation);
        }
    }

    @Override
    protected void onDisplayDistanceChanged(int distanceXToDisplay, int distanceYToDisplay, int dx, int dy) {
        if (!mActivityTranslucentUtil.isTranslucent()) {
            return;
        }
        if (mPreviousActivityContentView != null) {
            int translation = 0;
            switch (mDirection) {
                case DIRECTION_LEFT:    translation = initTranslation + (int) (mWidth * mProgress * mRelativeMoveFactor); break;
                case DIRECTION_RIGHT:   translation = initTranslation - (int) (mWidth * mProgress * mRelativeMoveFactor); break;
                case DIRECTION_TOP:     translation = initTranslation + (int) (mHeight * mProgress * mRelativeMoveFactor); break;
                case DIRECTION_BOTTOM:  translation = initTranslation - (int) (mHeight * mProgress * mRelativeMoveFactor); break;
                default:
            }
            movePreviousActivityContentView(translation);
        }
        boolean horizontal = (mDirection & DIRECTION_HORIZONTAL) > 0;
        View contentView = mWrapper.getContentView();
        if (contentView != null) {
            if (horizontal) {
                contentView.setTranslationX(distanceXToDisplay);
            } else {
                contentView.setTranslationY(distanceYToDisplay);
            }
        }
        layoutScrimView();
    }

    @Override
    protected void layoutContentView(View contentView) {
        if (contentView != null) {
            contentView.layout(0, 0, mWidth, mHeight);
        }
    }

    @Override
    public int clampDistanceVertical(int distanceY, int dy) {
        //resolve smooth problem while convert to transparent
        if (mActivityTranslucentUtil.isTranslucent()) {
            return super.clampDistanceVertical(distanceY, dy);
        }
        return 0;
    }

    @Override
    public int clampDistanceHorizontal(int distanceX, int dx) {
        //resolve smooth problem while convert to transparent
        if (mActivityTranslucentUtil.isTranslucent()) {
            return super.clampDistanceHorizontal(distanceX, dx);
        }
        return 0;
    }

}


另外,Activity的侧滑返回需要一个辅助类SmartSwipeBack,如下:

/**
 * A tool for achieving a one-line global activity swipe back via using some {@link SwipeConsumer}
 * simple usage:
 * 
 *
 //add swipe translucent back performance for all activities
 // (default direction: left, previous activity related factor:0.5F)
 SmartSwipeBack.activitySlidingBack(this, new SmartSwipeBack.ActivitySwipeBackFilter() {
 public boolean onFilter(Activity activity) {
 return !(activity instanceof MainActivity);
 }
 });

 //add swipe back like mobile QQ (activity keep stay and finish activity with release velocity)
 //SmartSwipeBack.activityStayBack(this, null);

 //add bezier swipe back like XiaoMi (swipe with bezier back consumer at edge of screen)
 //SmartSwipeBack.activityBezierBack(this, null);
 * 
 * @author billy.qi
 */
public class SmartSwipeBack {
    public static final ArrayList ACTIVITIES = new ArrayList<>();
    private static IPreviousFinder mPreviousFinder;

    public interface SwipeBackConsumerFactory {
        /**
         * Create SwipeConsumer to do swipe back business for activity
         * @param activity activity to wrap with swipe back
         * @return SwipeConsumer
         */
        SwipeConsumer createSwipeBackConsumer(Activity activity);
    }
    public interface ActivitySwipeBackFilter {
        /**
         * Determine whether the activity parameter should swipe back
         * @param activity The activity to wrap or not
         * @return true: need to wrap with swipe back, false: do not wrap
         */
        boolean onFilter(Activity activity);
    }

    public static void activityBack(Application application, SwipeBackConsumerFactory factory) {
        activityBack(application, factory, null);
    }

    /**
     * The core function for global activity swipe back
     * @param application application
     * @param factory factory to create SwipeConsumer for each Activity
     * @param filter filter of activity, to determine which activity should finish via swipe motion
     */
    public static void activityBack(Application application, SwipeBackConsumerFactory factory, ActivitySwipeBackFilter filter) {
        if (activitySwipeBackListener == null) {
            activitySwipeBackListener = new ActivitySwipeBackListener(factory, filter);
        } else {
            application.unregisterActivityLifecycleCallbacks(activitySwipeBackListener);
            activitySwipeBackListener.mFactory = factory;
            activitySwipeBackListener.mFilter = filter;
        }
        application.registerActivityLifecycleCallbacks(activitySwipeBackListener);
    }

    ////////////////////////////////////////////
    //
    //  swipe back with StayConsumer
    //
    ////////////////////////////////////////////

    public static void activityStayBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter) {
        final int edgeSize = SmartSwipe.dp2px(20, application);
        activityStayBack(application, filter, edgeSize, 0, SwipeConsumer.DIRECTION_LEFT);
    }

    public static void activityStayBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter, final int edgeSize, final int minVelocity, final int direction) {
        SmartSwipeBack.activityBack(application, new SwipeBackConsumerFactory() {
            @Override
            public SwipeConsumer createSwipeBackConsumer(final Activity activity) {
                return new StayConsumer()
                        .setMinVelocity(minVelocity)
                        .setEdgeSize(edgeSize)
                        .enableDirection(direction)
                        .addListener(new SimpleSwipeListener() {
                            @Override
                            public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
                                if (activity != null) {
                                    activity.finish();
                                }
                            }
                        });
            }
        }, filter);
    }

    ////////////////////////////////////////////
    //
    //  swipe back with ActivitySlidingBackConsumer
    //
    ////////////////////////////////////////////

    public static void activitySlidingBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter) {
        final float factor = 0.5f;
        // with default scrimColor: transparent
        activitySlidingBack(application, filter, factor);
    }

    public static void activitySlidingBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter, float factor) {
        //default edge size
        final int edgeSize = SmartSwipe.dp2px(20, application);
        final int shadowColor = 0x80000000;
        final int shadowSize = SmartSwipe.dp2px(10, application);
        final int direction = SwipeConsumer.DIRECTION_LEFT;
        activitySlidingBack(application, filter, edgeSize, Color.TRANSPARENT, shadowColor, shadowSize, factor, direction);
    }

    public static void activitySlidingBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter
            , final int edgeSize, final int scrimColor, final int shadowColor, final int shadowSize
            , final float factor, final int direction) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            //if sdk version is less than 21, the compatibility of ActivitySlidingBackConsumer is not good enough
            //use StayConsumer instead for android sdk version <= 20
            activityStayBack(application, filter, edgeSize, 0, direction);
        } else {
            activityBack(application, new SwipeBackConsumerFactory() {
                @Override
                public SwipeConsumer createSwipeBackConsumer(final Activity activity) {
                    return new ActivitySlidingBackConsumer(activity)
                            .setRelativeMoveFactor(factor)
                            .setScrimColor(scrimColor)
                            .setShadowColor(shadowColor)
                            .setShadowSize(shadowSize)
                            .setEdgeSize(edgeSize)
                            .enableDirection(direction)
                            .addListener(new SimpleSwipeListener(){
                                @Override
                                public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
                                    if (activity != null) {
                                        activity.finish();
                                        activity.overridePendingTransition(R.anim.anim_none, R.anim.anim_none);
                                    }
                                }
                            });
                }
            }, filter);
        }
    }

    ////////////////////////////////////////
    //
    //  swipe back with BezierBackConsumer
    //
    ////////////////////////////////////////

    public static void activityBezierBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter) {
        final int edgeSize = SmartSwipe.dp2px(20, application);
        activityBezierBack(application, filter, edgeSize);
    }

    public static void activityBezierBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter, int edgeSize) {
        final int thickness = SmartSwipe.dp2px(30, application);
        final int size = SmartSwipe.dp2px(200, application);
        final int direction = SwipeConsumer.DIRECTION_LEFT;
        activityBezierBack(application, filter, edgeSize, size, thickness, Color.BLACK, Color.WHITE, direction);
    }

    public static void activityBezierBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter
            , final int edgeSize, final int size, final int thickness, final int color, final int arrowColor, final int direction) {
        SmartSwipeBack.activityBack(application, new SwipeBackConsumerFactory() {
            @Override
            public SwipeConsumer createSwipeBackConsumer(final Activity activity) {
                return new BezierBackConsumer()
                        .setColor(color)
                        .setArrowColor(arrowColor)
                        .setSize(size)
                        .setOpenDistance(thickness)
                        .addListener(new SimpleSwipeListener() {
                            @Override
                            public void onSwipeRelease(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction, float progress, float xVelocity, float yVelocity) {
                                if (progress >= 1) {
                                    activity.finish();
                                }
                            }
                        })
                        .setEdgeSize(edgeSize)
                        .enableDirection(direction);
            }
        }, filter);
    }

    ////////////////////////////////////////
    //
    //  swipe back with ActivityDoorBackConsumer
    //
    ////////////////////////////////////////

    public static void activityDoorBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter) {
        final int edgeSize = SmartSwipe.dp2px(20, application);
        final int scrimColor = 0x80000000;
        final boolean refreshable = true;
        activityDoorBack(application, filter, SwipeConsumer.DIRECTION_LEFT, edgeSize, scrimColor, refreshable);
    }

    public static void activityDoorBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter
            , final int direction, final int edgeSize, final int scrimColor, final boolean refreshable) {
        SmartSwipeBack.activityBack(application, new SwipeBackConsumerFactory() {
            @Override
            public SwipeConsumer createSwipeBackConsumer(final Activity activity) {
                return new ActivityDoorBackConsumer(activity)
                        .setRefreshable(refreshable)
                        .setScrimColor(scrimColor)
                        .enableDirection(direction)
                        .setEdgeSize(edgeSize)
                        .addListener(new SimpleSwipeListener() {
                            @Override
                            public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
                                activity.finish();
                                activity.overridePendingTransition(R.anim.anim_none, R.anim.anim_none);
                            }
                        });
            }
        }, filter);
    }

    ////////////////////////////////////////
    //
    //  swipe back with ActivityShuttersBackConsumer
    //
    ////////////////////////////////////////

    public static void activityShuttersBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter) {
        final int edgeSize = SmartSwipe.dp2px(20, application);
        final int scrimColor = 0x80000000;
        final boolean refreshable = true;
        activityShuttersBack(application, filter, SwipeConsumer.DIRECTION_LEFT, edgeSize, scrimColor, refreshable);
    }

    public static void activityShuttersBack(Application application, SmartSwipeBack.ActivitySwipeBackFilter filter
            , final int direction, final int edgeSize, final int scrimColor, final boolean refreshable) {
        SmartSwipeBack.activityBack(application, new SwipeBackConsumerFactory() {
            @Override
            public SwipeConsumer createSwipeBackConsumer(final Activity activity) {
                return new ActivityShuttersBackConsumer(activity)
                        .setRefreshable(refreshable)
                        .setScrimColor(scrimColor)
                        .enableDirection(direction)
                        .setEdgeSize(edgeSize)
                        .addListener(new SimpleSwipeListener() {
                            @Override
                            public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
                                activity.finish();
                                activity.overridePendingTransition(R.anim.anim_none, R.anim.anim_none);
                            }
                        });
            }
        }, filter);
    }

    private static ActivitySwipeBackListener activitySwipeBackListener;

    public static class ActivitySwipeBackListener implements Application.ActivityLifecycleCallbacks {
        private SwipeBackConsumerFactory mFactory;
        private ActivitySwipeBackFilter mFilter;

        ActivitySwipeBackListener(SwipeBackConsumerFactory factory, ActivitySwipeBackFilter filter) {
            this.mFactory = factory;
            this.mFilter = filter;
        }

        @Override
        public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
            ACTIVITIES.add(activity);
            if (mFactory == null) {
                return;
            }
            if (mFilter != null && !mFilter.onFilter(activity)) {
                return;
            }
            SmartSwipe.wrap(activity).addConsumer(mFactory.createSwipeBackConsumer(activity));
        }
        @Override public void onActivityStarted(Activity activity) { }
        @Override public void onActivityResumed(Activity activity) { }
        @Override public void onActivityPaused(Activity activity) { }
        @Override public void onActivityStopped(Activity activity) { }
        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { }
        @Override public void onActivityDestroyed(Activity activity) {
            ACTIVITIES.remove(activity);
        }
    }

    /**
     * find previous activity
     * @param fromActivity the given activity to find its previous
     * @return the previous activity if exists
     * @see ActivitySlidingBackConsumer
     */
    public static Activity findPreviousActivity(Activity fromActivity) {
        if (mPreviousFinder != null) {
            return mPreviousFinder.findPreviousActivity(fromActivity);
        }
        if (fromActivity != null) {
            int index = ACTIVITIES.indexOf(fromActivity);
            if (index > 0) {
                return ACTIVITIES.get(index - 1);
            }
        }
        return null;
    }

    public static void setPreviousFinder(IPreviousFinder previousFinder) {
        mPreviousFinder = previousFinder;
    }

    public static interface IPreviousFinder {
        /**
         * find the previous activity for the given activity
         * @param fromActivity activity given
         * @return the previous activity
         */
        Activity findPreviousActivity(Activity fromActivity);
    }
}

代码实现如下:

    SmartSwipe.wrap(this)
            .addConsumer(new ActivitySlidingBackConsumer(this))
            .setRelativeMoveFactor(0.5f)
            .enableLeft();

[本章完...]

你可能感兴趣的:(侧滑效果[第十二篇]:侧滑框架SmartSwipe之仿微信返回效果)