Expandable ListView Side Slide Delete

Keywords: Android xml encoding

Expandable ListView Side Slide Delete

Recently, there is a need for work, similar to the QQ folding effect, of course, this control is Expandable ListView first thought of, but in the process of use, users put forward new requirements, need to add the side-sliding deletion function, what to do? I also looked at some other processing schemes on the Internet, but the effect is not ideal, and finally with the help of my colleagues through HorizontalScrollView implementation
1. There are two itme layout files for ExpandableListView, group item and subitem. Here we use subitem to sideslide. First we look at the layout file

<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
                      android:id="@+id/scrollView_item"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:descendantFocusability="blocksDescendants"
                      android:overScrollMode="never"
                      android:scrollbars="none">

    <LinearLayout
        android:id="@+id/ll_group_control"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/activity_item_margin"
        android:orientation="horizontal">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/activity_item_margin"
            android:background="@mipmap/background_device_one"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv_linajie"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="@dimen/margin_size_10"
                android:src="@mipmap/lianjie"/>

            <TextView
                android:id="@+id/child_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="5dp"
                android:layout_toRightOf="@id/iv_linajie"
                android:text="This is a child item"
                android:textColor="@color/write"
                android:textSize="@dimen/margin_size_20"/>

        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/img_delete"
            android:layout_width="70dp"
            android:layout_height="match_parent"
            android:background="@mipmap/delete_diban">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@mipmap/jianhao"/>

        </RelativeLayout>

    </LinearLayout>

</HorizontalScrollView>


2. First we define several interfaces

public interface OnAddDeviceListener {


        //Click Event
        void OnChildClick(int groupPosition, int childPosition);
        //Side Slide Delete Event
        void OnChildDel(int groupPosition, int childPosition);
        //Long press event
        void OnChildLongClick(int groupPosition, int childPosition);


    }


    public void setOnAddDeviceListener(OnAddDeviceListener l) {
        this.listener = l;

    }

    private OnAddDeviceListener listener;

There must be a lot of questions here. Defining a side-slip callback is reasonably enough. Why bother with defining clicks and long-click events? One of the questions here is that when dealing with a side-slip event through HorizontalScrollView, it will duplicate its onTouch event, which will invalidate the click event of the control itself, so here we need to define this by ourselvesSeveral events

  1. The adapter handles, omits other code, and directly handles getChildView methods related to subclasses, as follows
 //  Get the view displayed by the subitem
    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View view, ViewGroup parent) {
        if (view == null) {
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.child_item, null);
        }
        view.setTag(R.layout.parent_item, groupPosition);
        view.setTag(R.layout.child_item, childPosition);

        //Initialize the HorizontalScrollView control here and set the TAG tag to groupPosition+childPosition because of parameters passed in subsequent data callbacks
        HorizontalScrollView scrollView_item = (HorizontalScrollView) view.findViewById(R.id.scrollView_item);
        scrollView_item.setTag(groupPosition + "_" + childPosition);

        //This is of course our SideSlide delete event
        RelativeLayout img_delete = (RelativeLayout) view.findViewById(R.id.img_delete);
        img_delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (listener != null)
                    listener.OnChildDel(groupPosition, childPosition);
            }
        });
        scrollView_item.setOnTouchListener(new OnTouchListener() {
            private float startX = 0;

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                int x = (int) event.getX();
                int y = (int) event.getY();
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        // If there is an itemView with a Delete button, let it slide back and lock the touch. Unlocking occurs in the dispatchTouchEvent of the parent component
                        if (mScrollView != null) {
                            scrollView(mScrollView, HorizontalScrollView.FOCUS_LEFT);
                            mScrollView = null;
                            mLockOnTouch = true;
                            return true;
                        }
                        startX = event.getX();


                        //Press down, default start long press event

                        mLastMotionX = x;
                        mLastMotionY = y;
                        isMoved = false;
                        //Open the thread for event monitoring, which is the effect of the timer
                        handler.postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());
                        tag = (String) v.getTag();

                        break;
                    case  MotionEvent.ACTION_MOVE:

                        if (isMoved) break;
                        //Detects whether press state moves, releases long press event threads if limit is exceeded
                        if (Math.abs(mLastMotionX - x) > TOUCH_SLOP
                                || Math.abs(mLastMotionY - y) > TOUCH_SLOP_Y) {
                            //Move beyond threshold means move
                            isMoved = true;
                            handler.removeCallbacks(mLongPressRunnable);
                            iskey = true;
                        }

                        break;
                    case MotionEvent.ACTION_UP:
                        HorizontalScrollView view = (HorizontalScrollView) v;
                        //Get the horizontal coordinates when you release.
                        // Slide 100 pixels to the left and pop up the Delete button
                        if (startX > event.getX() + 100) {
                            startX = 0;// Restore startX value to prevent confusion because an event handling object is common
                            //Call the sliding method and move right
                            scrollView(view, HorizontalScrollView.FOCUS_RIGHT);
                            mScrollView = view;
//                        return true;
                        } else {
                            //Restore item state
                            if (Math.abs(event.getX()-startX)!=0) {
                                scrollView(view, HorizontalScrollView.FOCUS_LEFT);
                            }else{
                                //Click on an event to identify a long press event when iskey is false
                                if (listener != null && iskey) {
                                    String TAG = (String) v.getTag();
                                    String[] tags = TAG.split("_");
                                    listener.OnChildClick(Integer.valueOf(tags[0]), Integer.valueOf(tags[1]));
                                }


                            }
                        }
                        //Of course, you need to cancel the long press event after lifting
                        handler.removeCallbacks(mLongPressRunnable);
                        iskey = true;

                        break;
                }
                return false;

            }
        });

        return view;
    }

Timer threads and variables are as follows

    //Record coordinate information
    private int mLastMotionX, mLastMotionY;
    //Is it moved
    private boolean isMoved;
    //Long press runnable
    private Runnable mLongPressRunnable;
    //Moving threshold
    private final int TOUCH_SLOP = 20;
    //Y-Axis Moving Threshold
    private final int TOUCH_SLOP_Y = 4;
    //Distinguish click events from long press events
    private boolean iskey = true;
    private String tag;

    //Long press runnable
    private Runnable mLongPressRunnable = new Runnable() {

            @Override
            public void run() {

                handler.sendMessage(new Message());
                iskey = false;
            }
        };

Callback function for handling events in callback handle

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            try {
                String[] tags = tag.split("_");
                if (listener != null) {
                    if (tags.length == 2) {
                        //item Long By Event
                        listener.OnChildLongClick(Integer.valueOf(tags[0]), Integer.valueOf(tags[1]));
                    } 
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }

        }
    };

If necessary, you can write onTouch directly into the HorizontalScrollView custom control to improve the simplicity of the code. At the end of this function, long press events, side sliding deletions and click events are added, and group item s can also add side sliding, just like this

Posted by lady_bug on Thu, 20 Jun 2019 10:32:41 -0700