[Android event distribution] ItemTouchHelper implements side sliding deletion

Android event distribution series article directory

[Android Event Distribution] Event distribution source code analysis (the driver layer passes events through interrupts | WindowManagerService passes events to the View layer) [Android Event Distribution]Event Distribution Source Code Analysis (Event Delivery at Each Level in Activity | Activity -> PhoneWindow -> DecorView -> ViewGroup ) [Android Event Distribution] Event Distribution Source Code Analysis (ViewGroup Event Delivery Mechanism 1) [Android Event Distribution] Event Distribution Source Code Analysis (ViewGroup Event Delivery Mechanism 2) [Android Event Distribution] Event Distribution Source Code Analysis (ViewGroup Event Delivery Mechanism 3) [Android Event Distribution] Event Distribution Source Code Analysis ( ViewGroup Event Delivery Mechanism IV | View Event Delivery Mechanism ) [Android Event Distribution] Event Distribution Source Code Analysis (ViewGroup Event Delivery Mechanism 5) [Android Event Distribution] Event Distribution Source Code Analysis (ViewGroup Event Delivery Mechanism 6) [Android Event Distribution] Event Distribution Source Code Analysis (ViewGroup Event Delivery Mechanism VII)

[Android event distribution] Introduction to ItemTouchHelper (drag/slide event | ItemTouchHelper.Callback callback) [Android event distribution]ItemTouchHelper realizes sliding deletion (set sliding direction | enable sliding operation | sliding distance judgment | sliding speed judgment | set animation time | set side sliding trigger operation) [Android event distribution] ItemTouchHelper implements drag sorting (set sliding direction | enable long press drag function | drag distance judgment | set drag trigger operation)

Article directory

1. ItemTouchHelper.Callback configuration slide delete

1. Set the mobile flag (drag/slide)

Rewrite the getMovementFlags method of ItemTouchHelper.Callback, and set the sliding/dragging flag in this method;

Swipe/drag flag, you can use ItemTouchHelper.UP , ItemTouchHelper.DOWN , ItemTouchHelper.LEFT , ItemTouchHelper.RIGHT , to get or operate;

        // Set the drag direction, set up and down drag events here
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        // Set the sliding direction, here set the left and right sideslip events
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
copy

Then pass the dragging flag and sliding flag into the makeMovementFlags method to get a movement flag as the return value of the getMovementFlags method;

makeMovementFlags(dragFlags, swipeFlags);
copy
public class Callback extends ItemTouchHelper.Callback {
    /**
     * Set up, down, left, and right actions
     * Dragging in a specific direction can only be applied if the setting of the specified direction is turned on here
     * @param recyclerView
     * @param viewHolder
     * @return
     */
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView,
                                @NonNull RecyclerView.ViewHolder viewHolder) {
        // Set the drag direction, set up and down drag events here
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        // Set the sliding direction, here set the left and right sideslip events
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        // Apply drag and swipe settings
        return makeMovementFlags(dragFlags, swipeFlags);
    }
}
copy

2. Enable swipe action

Rewrite the isItemViewSwipeEnabled method of ItemTouchHelper.Callback, set the return value of this method to true, and enable the swipe operation;

public class Callback extends ItemTouchHelper.Callback {
    /**
     * Whether to enable swipe operation
     * @return Whether to enable true enable, false not enable
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }
}
copy

3. Sliding distance determination setting

Rewrite the getSwipeThreshold method of ItemTouchHelper.Callback, set the user's swipe distance, and set the proportional value, and the return value is 0.5, which means that half of the swipe width/height will trigger the side swipe onSwiped method;

public class Callback extends ItemTouchHelper.Callback {
    /**
     * The user's sliding distance, set the proportional value, and the return value is 0.5, which means half of the sliding width/height, and then the side sliding onSwiped method is triggered
     * @param viewHolder
     * @return
     */
    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return 0.5f;
    }
}
copy

The sliding range set in the above case is 0.5f, and the sliding direction set in the getMovementFlags method is left and right sliding, so in this case, the sliding range exceeds 0.5 times the width of the entry component in the horizontal direction, and the side sliding deletion will take effect;

In the following operations, if the slide does not exceed 0.5 times the width of the component in the horizontal direction, the slide delete will not take effect;

In the following operations, if the sliding range in the horizontal direction exceeds 0.5 times, the side sliding deletion will take effect;

Sideslip judgment: There are two sideslip judgment conditions here, and if any one is met, the sideslip deletion will be triggered; ① Condition 1: The swipe distance set in the getSwipeThreshold method, if the swipe exceeds 0.5 swipe range, the side swipe deletion will be triggered; ② Condition 2: The sliding speed set in the getSwipeEscapeVelocity method, if the speed exceeds 5 pixels per second in the horizontal direction, triggers side-swipe deletion;

4. Sliding speed determination setting

Rewrite the getSwipeEscapeVelocity method of ItemTouchHelper.Callback to set the user's swipe judgment speed, the unit is the number of pixels moved per second, and it can be judged as a swipe only after reaching this speed;

public class Callback extends ItemTouchHelper.Callback {
    /**
     * Sliding judgment speed, the number of pixels moving per second, only after reaching this speed can it be judged as sliding
     * @param defaultValue
     * @return
     */
    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return 5f;
    }
}
copy

Sideslip judgment: There are two sideslip judgment conditions here, and if any one is met, the sideslip deletion will be triggered; ① Condition 1: The swipe distance set in the getSwipeThreshold method, if the swipe exceeds 0.5 swipe range, the side swipe deletion will be triggered; ② Condition 2: The sliding speed set in the getSwipeEscapeVelocity method, if the speed exceeds 5 pixels per second in the horizontal direction, triggers side-swipe deletion;

5. Set animation time

Override the getAnimationDuration method of ItemTouchHelper.Callback to set the animation duration after the user's finger leaves, in milliseconds ms;

public class Callback extends ItemTouchHelper.Callback {
    /**
     * The duration of the animation after the finger leaves
     * @param recyclerView
     * @param animationType
     * @param animateDx
     * @param animateDy
     * @return
     */
    @Override
    public long getAnimationDuration(@NonNull RecyclerView recyclerView,
                                     int animationType,
                                     float animateDx, float animateDy) {
        return 200L;
    }
}
copy

6. Set the side-swipe delete trigger operation

Rewrite the onSwiped method of ItemTouchHelper.Callback, this method will be called after the user's side swipe is judged successfully, and this method will not be called if the side swipe is not judged successfully;

Sideslip judgment: There are two sideslip judgment conditions here, and if any one is met, the sideslip deletion will be triggered; ① Condition 1: The swipe distance set in the getSwipeThreshold method, if the swipe exceeds 0.5 swipe range, the side swipe deletion will be triggered; ② Condition 2: The sliding speed set in the getSwipeEscapeVelocity method, if the speed exceeds 5 pixels per second in the horizontal direction, triggers side-swipe deletion; You can set only one or both of them;

public class Callback extends ItemTouchHelper.Callback {
    /**
     * Callback operation when sliding
     * @param viewHolder
     * @param direction
     */
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        Log.i(TAG, "Trigger side swipe to delete entry");
        // Swipe the specified distance, and after reaching a certain range, the method callback will be triggered
        // What is done here is the sliding delete function, directly delete the sliding item
        // In this method, the specified item is deleted and the interface is refreshed
        mAdapter.deleteItem(viewHolder.getAdapterPosition());
    }
}
copy

7. Delete operation in RecyclerView.Adapter adapter

Delete the elements in the data list, and call notifyItemRemoved to trigger the deletion animation;

    public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
        /**
         * The method called by the delete element
         * @param position
         */
        public void deleteItem(int position) {
            names.remove(position);
            notifyItemRemoved(position);
        }
	}
copy

3. Complete code implementation

1. Main interface

package kim.hsl.recyclerview;

import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    /**
     * data source
     */
    private ArrayList<String> names = new ArrayList<String>();

    /**
     * The current list of RecyclerView s
     */
    private RecyclerView recycler_view;

    /**
     * layout manager
     */
    private LinearLayoutManager layoutManager;

    /**
     * adapter
     */
    private Adapter adapter;

    /**
     * Add drag handling
     */
    private ItemTouchHelper mItemTouchHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialization data
        initData();

        //1. Get the RecyclerView from the layout
        recycler_view = findViewById(R.id.recycler_view);

        //2. Create and set up the layout manager
        //Create a layout manager
        layoutManager = new LinearLayoutManager(
                this,
                RecyclerView.VERTICAL,
                false);

        //Set layout manager
        recycler_view.setLayoutManager(layoutManager);

        // set margins
        recycler_view.addItemDecoration(new ItemDecoration());

        //3. Create and set up the list adapter
        adapter = new Adapter();
        recycler_view.setAdapter(adapter);

        //4. Add drag event
        Callback callback = new Callback(adapter);
        mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(recycler_view);
    }

    /**
     * Initialization data
     */
    private void initData(){
        names.add("Song Jiang");
        names.add("Lu Junyi");
        names.add("Wu Yong");
        names.add("Gongsun Sheng");
        names.add("Guan Sheng");
        names.add("Lin Chong");
        names.add("Qin Ming");
        names.add("Hu Yanzhuo");
        names.add("Huarong");
        names.add("Chai Jin");
        names.add("Li Ying");
        names.add("Zhu Dong");
        names.add("Lu Zhishen");
        names.add("Wu Song");
        names.add("Dong Ping");
        names.add("Zhang Qing");
        names.add("Yang Zhi");
        names.add("Xu Ning");
        names.add("Suo Chao");
    }

    /**
     * RecyclerView adapter
     */
    public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {

        private RecyclerView mRecyclerView;

        @Override
        public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            this.mRecyclerView = recyclerView;
        }

        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View root_view = LayoutInflater.from(MainActivity.this)
                    .inflate(R.layout.item_recyclerview, parent, false);
            return new ViewHolder(root_view);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.text.setText("" + names.get(position));
        }

        @Override
        public int getItemCount() {
            return names.size();
        }

        public class ViewHolder extends RecyclerView.ViewHolder {
            TextView text;
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
                text = itemView.findViewById(R.id.text);
            }
        }

        /**
         * The method called by the delete element
         * @param position
         */
        public void deleteItem(int position) {
            names.remove(position);
            notifyItemRemoved(position);
        }
    }

}
copy

2. ItemTouchHelper.Callback callback class

package kim.hsl.recyclerview;

import android.util.Log;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

public class Callback extends ItemTouchHelper.Callback {

    private static final String TAG = "Callback";

    private MainActivity.Adapter mAdapter;

    public Callback(MainActivity.Adapter mAdapter) {
        this.mAdapter = mAdapter;
    }

    /**
     * Set up, down, left, and right actions
     * Dragging in a specific direction can only be applied if the setting of the specified direction is turned on here
     * @param recyclerView
     * @param viewHolder
     * @return
     */
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView,
                                @NonNull RecyclerView.ViewHolder viewHolder) {
        // Set the drag direction, set up and down drag events here
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        // Set the sliding direction, here set the left and right sideslip events
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        // Apply drag and swipe settings
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    /*
        The following are drag related methods
     */

    /**
     * Whether to enable long press and drag function
     * @return
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    /**
     * Drag range setting
     * When the component moves more than this ratio in width/height, it is considered to be triggered by dragging, and dragging related operations are performed
     * @param viewHolder
     * @return
     */
    @Override
    public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        // In this case, the drag operation can only be performed up and down
        // The drag operation can be triggered when the drag exceeds 0.9 times the height of the item component
        return 0.9f;
    }

    /**
     * Listen for sliding events
     * Sliding Points Horizontal/Vertical Both Directions
     * @param recyclerView
     * @param viewHolder
     * @param target
     * @return
     */
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView,
                          @NonNull RecyclerView.ViewHolder viewHolder,
                          @NonNull RecyclerView.ViewHolder target) {
        // Exchange data after dragging, exchange data in Adapter in this method, and refresh the interface
        Log.i(TAG, "trigger drag swap entry");
        return true;
    }

    /*
        The following are sliding related methods
     */

    /**
     * Whether to enable swipe operation
     * @return Whether to enable true enable, false not enable
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    /**
     * The user's sliding distance, set the proportional value, and the return value is 0.5, which means half of the sliding width/height, and then the side sliding onSwiped method is triggered
     * @param viewHolder
     * @return
     */
    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return 0.5f;
    }

    /**
     * Sliding judgment speed, the number of pixels moving per second, only after reaching this speed can it be judged as sliding
     * @param defaultValue
     * @return
     */
    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return 5000f;
    }

    /**
     * The duration of the animation after the finger leaves
     * @param recyclerView
     * @param animationType
     * @param animateDx
     * @param animateDy
     * @return
     */
    @Override
    public long getAnimationDuration(@NonNull RecyclerView recyclerView,
                                     int animationType,
                                     float animateDx, float animateDy) {
        return 200L;
    }

    /**
     * Callback operation when sliding
     * @param viewHolder
     * @param direction
     */
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        Log.i(TAG, "Trigger side swipe to delete entry");
        // Swipe the specified distance, and after reaching a certain range, the method callback will be triggered
        // What is done here is the sliding delete function, directly delete the sliding item
        // In this method, the specified item is deleted and the interface is refreshed
        mAdapter.deleteItem(viewHolder.getAdapterPosition());
    }
}
copy

3. Execution effect

3. Blog Resources

Blog Resources :

Tags: Android animation source code analysis

Posted by LeZeNkO on Wed, 29 Mar 2023 12:42:42 +0530