ItemTouchHelper to realize interactive animation

Catalogue introduction

  • 01. Drag needs to realize functions
  • 02. Several important methods
  • 03. Simple implementation ideas
  • 04. Drag effect optimization
  • 05. Complete code display

Hot wire

  • Blog notes summary [from March 2016 to now], including Java foundation and in-depth knowledge points, Android technology blog, Python learning notes, etc., as well as bug summary in normal development. Of course, a large number of interview questions are collected after work, which are updated, maintained and corrected for a long time, and continuously improved Open source files are in markdown format! At the same time, it has also opened up the life blog. Since 12 years, it has accumulated a total of N articles [nearly 1 million words, successively moved to the Internet], please indicate the source of reprint, thank you!
  • Link address: https://github.com/yangchong211/yclogs
  • If you feel good, you can star for a moment, thank you! Of course, you are welcome to make suggestions. Everything starts from scratch. Quantitative changes lead to qualitative changes!

01. Drag needs to realize functions

  • The drag function is as follows
    • Long press item and drag to exchange position with other items
    • Press and hold the icon on the right side of the item and drag to exchange positions with other items
    • Slide the item on the left to make it transparent and narrow. When it exceeds the screen, other items will be added
    • Slide the item on the right to make it transparent and narrow. When it exceeds the screen, other items will be added

02. Several important methods

  • Several important methods
    • You need a custom class to implement the ItemTouchHelper.Callback class and override several of these methods
    Whether isLongPressDragEnabled can be sorted by drag and drop
     Is the isitemviewswipeenabled item slidable
     getMovementFlags when users drag or slide items, we need to tell the system the direction of sliding or dragging
     onMove callback when Item is dragged
     onSwiped when the View is removed by sliding
     onSelectedChanged triggered when an item is dragged or skidded
    

03. Simple implementation ideas

  • Code ideas in several methods
    • In order to meet the above functional requirements, in the getMovementFlags method, when users drag or slide items, we need to tell the system the direction of sliding or dragging. We know that only LinearLayoutManager and GridLayoutManager support dragging and sliding deletion, so we can distinguish the response according to the different layout managers.
    • In the onMove method, the callback logic of dragging is handled. When is it called? Called when an Item is dragged and sorted to another Item's location. Process the deleted logic in the onSwiped method [when the Item is slideously deleted to invisible]. In order to reduce code coupling, the interface listener callback can be used for external processing.
  • Position exchange with other item s when dragging up and down
    • ItemTouchHelper.Callback itself does not have the function of exchanging the positions of two items, but RecyclerView can. When dragging an item, we can exchange the data positions of the current item and another item, and then call the notifyItemMoved() method of RecyclerView to refresh the layout. At the same time, because RecyclerView comes with item animation, the above interaction effect can be completed.
  • Add other item s when sliding left and right out of the screen
    • Just delete the corresponding data when the item slides out of the screen, and then call the notifyItemRemoved() method of RecyclerView to refresh the layout.

04. Drag effect optimization

  • Drag optimization
    • Modify the background color when the item is dragged or skidded. When the action is over, restore the background color. In ItemTouchHelper.Callback, there are two corresponding methods: onSelectedChanged(), clearView(). So optimization can be put into these two methods.
    • How to reduce the transparency of items by sliding left and right? There are only two kinds of attribute animations for the item. In ItemTouchHelper.Callback, there is a method to get the displacement change when the item is dragged or slid, that is, onChildDraw() method, in which the item gradient and scale attribute animations are set.
    • If there is a problem, according to the above practice, there will be blank items left after deletion, so why does this happen? There are not two more blank data. They are normal data, but they are invisible. This is because the RecyclerView entry (itemView) is overlapped. Previously, transparency and reduction are set for itemView in onChildDraw() method, while only a few itemviews are fixed in a list. When the two transparent and reduced itemviews are used again, the transparency previously set is transparent The degree and height scale are already 0, so this happens. The solution is very simple. Just set the transparency and height scale of itemView after the item is removed

05. Complete code display

  • GitHub address of the code: https://github.com/yangchong211/YCRefreshView
  • The complete code is as follows
    /**
     * <pre>
     *     @author Yang Cheng
     *     blog  : https://github.com/yangchong211
     *     time  : 2017/5/2
     *     desc  : Customize ItemTouchHelper
     *     revise: Refer to the blog of Yan Zhengjie: https://blog.csdn.net/yanzhenjie1003/article/details/51935982
     * </pre>
     */
    public class ItemTouchHelpCallback extends ItemTouchHelper.Callback {
    
        /**
         * Item Operation callback to update UI and data source
         */
        private OnItemTouchCallbackListener onItemTouchCallbackListener;
        /**
         * Whether it can be dragged
         */
        private boolean isCanDrag = false;
        /**
         * Whether it can be slid
         */
        private boolean isCanSwipe = false;
        /**
         * Press and hold to drag the item's color
         */
        private int color = 0;
    
        public ItemTouchHelpCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) {
            this.onItemTouchCallbackListener = onItemTouchCallbackListener;
        }
    
        /**
         * Set whether it can be dragged
         *
         * @param canDrag Yes true, no false
         */
        public void setDragEnable(boolean canDrag) {
            isCanDrag = canDrag;
        }
    
        /**
         * Set whether it can be slid
         *
         * @param canSwipe Yes true, no false
         */
        public void setSwipeEnable(boolean canSwipe) {
            isCanSwipe = canSwipe;
        }
    
        /**
         * Set the color of drag item
         * @param color     colour
         */
        public void setColor(@ColorInt int color){
            this.color = color;
        }
    
        /**
         * Whether items can be dragged when they are long pressed
         *
         * @return                      true
         */
        @Override
        public boolean isLongPressDragEnabled() {
            return isCanDrag;
        }
    
        /**
         * Item Whether it can be slid (H: sliding left and right, V: sliding up and down)
         * isItemViewSwipeEnabled()Whether the return value can be dragged for sorting, true can be used, false can not be used
         * @return                      true
         */
        @Override
        public boolean isItemViewSwipeEnabled() {
            return isCanSwipe;
        }
    
        /**
         * When users drag or slide items, we need to tell the system the direction of sliding or dragging
         * Action marks: dragFlags and swipeFlags
         * dragFlags: Action identification of the scrolling direction of the list (for example, the vertical list is up and down, and the horizontal list is left and right)
         * wipeFlags: Action ID perpendicular to the scrolling direction of the list (for example, the vertical list is left and right, and the horizontal list is up and down)
         *
         * Idea: if you don't want to drag up and down, drag flags = 0
         *      If you don't want to slide left and right, you can set swipeFlags = 0
         *      The final action flags must be generated with the makeMovementFlags() method
         */
        @Override
        public int getMovementFlags(@NonNull RecyclerView recyclerView,
                                    @NonNull RecyclerView.ViewHolder viewHolder) {
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager) {
                // If the value of flag is 0, the function is turned off
                int dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
                        | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                int swipeFlag = 0;
                // create make
                return makeMovementFlags(dragFlag, swipeFlag);
            } else if (layoutManager instanceof LinearLayoutManager) {
                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
                int orientation = linearLayoutManager.getOrientation();
    
                int dragFlag = 0;
                int swipeFlag = 0;
    
                // For the convenience of understanding, it is divided into horizontal ListView and vertical ListView
                // In case of horizontal layout
                if (orientation == LinearLayoutManager.HORIZONTAL) {
                    swipeFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                    dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                } else if (orientation == LinearLayoutManager.VERTICAL) {
                    // If the layout is vertical, it is equivalent to ListView
                    dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                    swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                }
                //The first parameter is drag flag, and the second parameter is slide flag
                return makeMovementFlags(dragFlag, swipeFlag);
            }
            return 0;
        }
    
    
        /**
         * Callback when Item is dragged
         *
         * @param recyclerView          recyclerView
         * @param srcViewHolder         viewHolder of the currently dragged item
         * @param targetViewHolder      viewHolder of another item under the currently dragged item
         * @return                      Is it moved
         */
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView,
                              @NonNull RecyclerView.ViewHolder srcViewHolder,
                              @NonNull RecyclerView.ViewHolder targetViewHolder) {
            if (onItemTouchCallbackListener != null) {
                int srcPosition = srcViewHolder.getAdapterPosition();
                int targetPosition = targetViewHolder.getAdapterPosition();
                return onItemTouchCallbackListener.onMove(srcPosition, targetPosition);
            }
            return false;
        }
    
    
        /**
         * Triggered when item slips out (vertical list is sideslip, horizontal list is vertical slip)
         *
         * @param viewHolder            viewHolder
         * @param direction             Sliding direction
         */
        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            if (onItemTouchCallbackListener != null) {
                onItemTouchCallbackListener.onSwiped(viewHolder.getAdapterPosition());
            }
        }
    
        /**
         * Triggered when an item is dragged or skidded
         *
         * @param viewHolder            viewHolder
         * @param actionState           Status of current item
         */
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            super.onSelectedChanged(viewHolder, actionState);
            //Whether it's drag or sideslip, the background color will change
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                if (color==0){
                    viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext()
                            .getResources().getColor(android.R.color.darker_gray));
                }else {
                    viewHolder.itemView.setBackgroundColor(color);
                }
            }
        }
    
    
        /**
         * Triggered when the interactive animation of an item ends
         *
         * @param recyclerView          recyclerView
         * @param viewHolder            viewHolder
         */
        @Override
        public void clearView(@NonNull RecyclerView recyclerView,
                              @NonNull RecyclerView.ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
            viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources()
                    .getColor(android.R.color.white));
            viewHolder.itemView.setAlpha(1);
            viewHolder.itemView.setScaleY(1);
        }
    
    
        @Override
        public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
                                @NonNull RecyclerView.ViewHolder viewHolder,
                                float dX, float dY, int actionState, boolean isCurrentlyActive) {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
                float value = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
                viewHolder.itemView.setAlpha(value);
                viewHolder.itemView.setScaleY(value);
            }
        }
    
    
        public interface OnItemTouchCallbackListener {
            /**
             * When an Item is deleted by sliding
             *
             * @param adapterPosition   item position
             */
            void onSwiped(int adapterPosition);
    
            /**
             * Called back when two Item positions are interchanged
             *
             * @param srcPosition       position of dragged item
             * @param targetPosition    position of the Item of the destination
             * @return                  The developer should return true after handling the operation. If the developer does not handle the operation, it will return false
             */
            boolean onMove(int srcPosition, int targetPosition);
        }
    }
    
  • How to use, the code is as follows
    ItemTouchHelpCallback callback = new ItemTouchHelpCallback((srcPosition, targetPosition) -> {
            if (imageBeans != null) {
                try {
                    // Replace the location of the data Item in the data source. Change the position of the start and end positions in the list
                    Collections.swap(imageBeans, srcPosition, targetPosition);
                    // Update the location of items in the UI, mainly to show users the interaction effect
                    mAdapter.notifyItemMoved(srcPosition, targetPosition);
                } catch (Exception e){
                    e.printStackTrace();
                }
                return true;
            }
            return true;
        });
    callback.setDragEnable(true);
    callback.setSwipeEnable(true);
    callback.setColor(this.getResources().getColor(R.color.base_background_block));
    //Create a helper object, and callback listens for various statuses of recyclerView item
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
    try{
        //Associated with recyclerView, a helper object can only correspond to one recyclerView
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }catch (Exception e){
        e.printStackTrace();
    }
    

Open source library address [integrate most recyclerView use cases, you can download demo directly]: https://github.com/yangchong211/YCRefreshView

  • Recyclerview complex package library
    • It almost integrates most of the knowledge points in this series of blogs. Welcome to watch the blog again and practice again, step by step to realize the powerful library with simple functions
  • 01.RecyclerView
    • The structure of RecycleView, introduction to the simple use of RecycleView
  • 02.Adapter
    • The role of RecyclerView.Adapter, the description of commonly used rewriting methods, the observer mode of data change notification, view. notifyChanged(); source code
  • 03.ViewHolder
    • How to understand the function of ViewHolder. Stop calling onCreateViewHolder method after the number of ViewHolder objects is "enough". ViewHolder is simple encapsulation
  • 04.LayoutManager
    • What is the role of LayoutManager? Source code analysis of setLayoutManager
  • 05.SnapHelper
    • SnapHelper function, what is the flip operation, important methods of SnapHelper class,
  • 06.ItemTouchHelper
  • 07.SpanSizeLookup
    • How to use SpanSizeLookup, including list, 2-column grid and 3-column grid?
  • 08.ItemDecoration
    • Use of ItemDecoration, addItemDecoration() source code analysis
  • 09.RecycledViewPool
    • RecyclerViewPool is used to share views among multiple recyclerviews.
  • 11.RecyclerView pull-up loading
    • Add the slider event of recyclerView, pull up to load paging data, set the bottom footer layout of pull-up loading, show and hide the footer layout
  • 12.RecyclerView caching principle
    • RecyclerView's performance optimization is complex, such as layout optimization, caching, preloading, pool reuse, data refresh, etc
  • 13.SnapHelper source code analysis
    • SnapHelper is designed to support the alignment of RecyclerView, that is, by calculating and aligning the specified points of TargetView in RecyclerView or any pixel points in the container.
  • 16. Customize SnapHelper
    • Customize SnapHelper
  • 19. Custom ItemDecoration split line
    • You need a custom class to implement the RecyclerView.ItemDecoration class and choose to override the appropriate method
  • 22.RecyclerView problem summary
    • The difference between getLayoutPosition() and getAdapterPosition()
  • 23.RecyclerView slide conflict
    • 01. How to judge whether the RecyclerView control slides to the top and bottom
    • 02.RecyclerView nested RecyclerView entries auto roll up bugs
    • 03.ScrollView nested RecyclerView slide conflict
    • 04.ViewPager nesting horizontal RecyclerView horizontal slide to the bottom without sliding ViewPager
    • 05.RecyclerView nested RecyclerView slide conflict
    • 06.RecyclerView uses Glide to load pictures, which causes picture confusion. Solution
  • 24.ScrollView nesting RecyclerView problem
    • To embed one or more recyclerviews in NestedScrollView, there will be sliding conflicts, focus grabbing, incomplete display, etc. How to deal with it?

Other introductions

01. About blog summary link

02. About my blog

  • My personal website: www.yczbj.org, www.ycbjie.cn
  • github: https://github.com/yangchong211
  • Zhihu: https://www.zhihu.com/people/yczbj/activities
  • Jianshu: http://www.jianshu.com/u/b7b2c6ed9284
  • csdn: http://my.csdn.net/m0_37700275
  • Himalaya listening: http://www.ximalaya.com/zhubo/71989305/
  • Open source China: https://my.oschina.net/zbj1618/blog
  • Days spent online: http://www.jcodetrader.com/member/content'u list. PHP? Channelid = 1
  • Email: yangchong211@163.com
  • Alicloud blog: https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
  • Segmentfault headline: https://segmentfault.com/u/xiangjianyu/articles
  • Nuggets: https://juejin.im/user/5939433efe88c2006afa0c6e

Code case: https://github.com/yangchong211/YCRefreshView

170 original articles published, 72 praised, 110000 visitors+
Private letter follow

Tags: github Android Attribute Java

Posted on Fri, 14 Feb 2020 02:32:24 -0500 by haydndup