This article has been published exclusively by guolin_blog, an official wechat account

Reprint please indicate the source: juejin.cn/post/684490… This article is from: [Zhang Xutong’s Rare earth mining] (juejin.cn/user/905653…) Code portal: Click star if you like. Thank you for your github.com/mcxtzhang/S…


Not for the RecyclerView or ListView, for the Any ViewGroup.

This control does not rely on any parent layout, not RecyclerView, ListView, but any ViewGroup childView can use the side slide (delete) menu. Support for any ViewGroup, zero coupling, the easiest ever.

An overview of the

It has been 7 months since this control was used in the project and 2 months since it was first pushed to Github. (Earlier, I published an article. Portal: blog.csdn.net/zxt0601/art… , which describes in detail how the control V1.0 version is implemented.

During this period, many friends put forward some improvement suggestions in the comments and issues, such as support for setting the sliding direction (left and right), high imitation QQ interaction, support GridLayoutManager, and some bugs. It has been all fixed and repaired by me. And it’s packaged into the JITPack for easier import. Compared with the first edition, there are quite a few changes. So it will be sorted out, a new version.

This article starts with how to use it, and then describes the features it contains and the properties it supports. Finally, several difficulties and conflicts are explained.

Code portal: Click star if you like. Thank you for your github.com/mcxtzhang/S…

Here are a few giFs to give you a taste of the latest version of the charm (the following versions incidentally show optional two-way sliding)

ItemDecorationIndexBar + SwipeMenuLayout: (ItemDecorationIndexBar: Github.com/mcxtzhang/I…).

Android Special Version (non-blocking, you can still open the other side menu when the side menu is expanded, and the previous menu will automatically close) :

GridLayoutManager (compared to the code above, just modify the LayoutManager of RecyclerView.) :

LinearLayout (without any modification, LinearLayout can also be easily implemented in the side slide menu) :

IOS Interaction (blocking interaction, highly mimicking QQ, side-scrolling menu expansion, shielding all operations of other items) :

Use:

Step 1. Add the JitPack repository dependency to the project root build.gradle file.

    allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io"}}}Copy the code

Step 2. Add the dependency

    dependencies {
            compile 'com. Making. McXtzhang: SwipeDelMenuLayout: V1.2.1'
    }Copy the code

Step 3. Put the control on the outside of the ContentItem that needs to be swivelled and deleted, and arrange the ContentItem and menu successively in the control: So far you can use high imitation IOS, QQ sideslip delete menu function (sideslip menu click events are obtained by setting the ID, consistent with other controls, no further details)

In the Demo, my ContentItem was a TextView, so I nested the control around it and arranged the menu controls in the same order as the slide menu appeared.

<? xml version="1.0" encoding="utf-8"? > <com.mcxtzhang.swipemenulib.SwipeMenuLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="100dp" android:clickable="true" android:paddingBottom="1dp"> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:background="?android:attr/selectableItemBackground" android:gravity="center" Android :text=" Project I am arbitrarily complex original ContentItem layout "/> <! <Button android:id="@+id/btnTop" Android :layout_width="60dp" Android :layout_height="match_parent" Android :background="#d9dee4" Android :text=" #d9dee4" android:textColor="@android:color/white"/> <Button id = 1 android:id="@+id/btnUnRead" android:layout_width="120dp" android:layout_height="match_parent" Android :background="#ecd50a" Android :text=" # ecd50A "Android :background="# ecd50A" Android :clickable="true" Android :text=" @android:color/white"/> <Button android:id="@+id/btnDelete" android:layout_width="60dp" android:layout_height="match_parent" Android :background="@color/red_ff4a57" Android :text=" delete "Android :textColor="@android:color/white"/> </com.mcxtzhang.swipemenulib.SwipeMenuLayout>Copy the code

Supported attributes:

1 Use the isIos variable to control whether IOS blocking interaction is enabled by default. 2 Use isSwipeEnable to control whether to enable the right slide menu, which is enabled by default. IsLeftSwipe isLeftSwipe isLeftSwipe isLeftSwipe isLeftSwipe isLeftSwipe isLeftSwipe

There are two ways to set this:

<com.mcxtzhang.swipemenulib.SwipeMenuLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:ios="false"
    app:leftSwipe="true"
    app:swipeEnable="true">Copy the code

Two: Java code:

// This sentence turns off the blocking interaction in IOS and turns on the swipe left, swipe right to disable the swipe off menu
((SwipeMenuLayout) holder.itemView).setIos(false).setLeftSwipe(position % 2= =0 ? true : false).setSwipeEnable(false);Copy the code

Supported features:

  • 2+ slideshow menus will not be expanded simultaneously. (At most, a slide-out menu appears on the visible screen.)
  • Prohibit the parent control from sliding up and down during sideslip.
  • Slide with more than one finger at a time, shielding the fingers behind the touch.
  • Added a get() method for viewChache that closes the unfolding sideslip menu when the outer space is clicked.
  • The width of the first subitem (ContentItem) is the width of the control

Checklist for each update:

Due to continuous iteration, new bugs may occur after a feature is completed and a bug is fixed. So, organize a checkList for verification after each iteration and push it to github library only when the checkList is passed.

project note validation
isIos The following features work when you switch to IOS blocking interaction mode and Android features non-blocking interaction mode
isSwipeEnable Whether to disable the sideslip function
isLeftSwipe Whether bidirectional sliding is supported
ContentItem Content Click
ContentItem Content can be long pressed
ContentItem is not clickable when the sideslip menu is displayed
The ContentItem cannot be long pressed when the scroll menu is displayed
When the sideslip menu is displayed, the sideslip menu can be clicked
When the scroll menu is displayed, click the ContentItem area to close the menu
Mask the long press event during sideslip
The ContentItem click event should not be triggered by sliding to close the menu

Difficulties and conflict resolution:

1 Long press of ContentItem conflicts with sideslip of this control. I started with the same idea, which was always to figure out where my finger is going to start, where my finger is going to fall, and to block out some operations. When the control function is more and more large, the calculation began to be complex, but also prone to error. I stumbled through it, but today I came up with another idea: to do this by disabling the longClickable property of the subview. So I refactor this part of the code, first use Git to look at the previous commit, remove that part of the code, and add the following functions to smoothExpand() and smoothClose() :

        //2016 11 13 Add Side slider menu to expand, block content long press
        if (null! = mContentView) { mContentView.setLongClickable(true);
        }Copy the code
        //2016 11 13 Add Side slider menu to expand, block content long press
        if (null! = mContentView) { mContentView.setLongClickable(true);
        }Copy the code

The code is as simple as that, and I thought of such a simple solution just a few hours ago, which is one of the reasons why I’m going through this article again and documenting some of the changes to the book control.

2 how to support any parent control this is one of the coolest charm of this control, in the previous article, I described the implementation process in detail. To sum up, I use a static variable to save the View that is currently being expanded, so that I can predict when I’m doing something. If there is a conflict, for example, when two side menus appear on the screen, the previous menu is automatically closed.

The code is as follows:

    // Stores the View that is currently being expanded
    private static SwipeMenuLayout mViewCache;Copy the code

ActionDown of dispatchTouchEvent() :

                    // If down, View is different from CacheView, restore it immediately. And set it to null
                    if(mViewCache ! =null) {
                        if(mViewCache ! =this) {
                            mViewCache.smoothClose();
                        }
                        // The outer layout will not be swiped up or down as long as a slider menu is open
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }Copy the code

SmoothExpand () and close smoothClose() functions in the side slider menu:

    // Expand to add ViewCache:
    mViewCache = SwipeMenuLayout.this;Copy the code
    // Close to null
    mViewCache = null;Copy the code

OnDetachedFromWindow () :

    // Each time ViewDetach is executed, check whether the ViewCache is itself. If it is, close the slide menu and set ViewCache to null.
    // Reason: 1 to prevent memory leaks (ViewCache is static)
    // After 2 swipes to remove the Recycler View, the next View to be Recycler should be normal, not expanded.
    @Override
    protected void onDetachedFromWindow() {
        if (this == mViewCache) {
            mViewCache.smoothClose();
            mViewCache = null;
        }
        super.onDetachedFromWindow();
    }Copy the code

3. Solve multi-finger sliding conflict: use a Boolean value of flag to judge whether to continue to accept touch events in ActionDown: the code is as follows:

    // To prevent multiple fingers from sliding my flag in each down judgment, the touch event is cleared
    private static boolean isTouching;Copy the code

ActionDown of dispatchTouchEvent() :

    if (isTouching) {// Return false if other fingers touch it. Such subsequent move.. Events won't be looking for this View anymore.
        return false;
    } else {
        isTouching = true;// The first finger touched, change the sign quickly, swear sovereignty.
    }Copy the code

ActionUp:

    isTouching = false;// No more fingers touching meCopy the code

After all, it is rare to use the slider menu in grid layout in the project, so I simplified the scene at the beginning and set the width of this control to be the width-padding of the parent control. Later, children shoes proposed to support the grid layout, at the beginning OF my ideas also took a detour, I also want to build a MatchParent’s MeasureSpec, and then passed to the parent control (GridView, RecyclerView) for measurement. The width of the ContentView is used as the width of the control. In this way, when the layout side slide menu is displayed, the side slide menu layout will be invisible. Only by sliding can it be displayed. In onMeasure() :


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //2016 11 09 add, for GridLayoutManager, will use the width of the first subitem as the width of the control
        int contentWidth = 0;
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            if(childView.getVisibility() ! = GONE) { measureChildWithMargins(childView, widthMeasureSpec,0, heightMeasureSpec, 0);
                final MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();
                mHeight = Math.max(mHeight, childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                if (i > 0) {// The first layout is Left Item and the second is RightMenu
                    mRightMenuWidths += childView.getMeasuredWidth();
                } else {
                    contentWidth = childView.getMeasuredWidth();
                }
            }
        }
        setMeasuredDimension(contentWidth, mHeight);// The width takes the width of the first Item(Content)
    }Copy the code

In onLayout(), order layoutchildView.

conclusion

Above is the control of the recent or we are interested in some of the points of detail, more detailed explanation can go to the previous article to watch, or go to Github download source browsing. The above address: blog.csdn.net/zxt0601/art… Code portal: Click star if you like. Thank you for your github.com/mcxtzhang/S…

If you have any problems, please give us more feedback.