天天看點

android 仿IOS添加小元件的拖拽排序清單,使用SwipeRecyclerView前言幹活Github完事

android 仿IOS添加小元件的拖拽排序清單,使用SwipeRecyclerView

  • 前言
  • 幹活
    • 找到合适的輪子
    • 添加依賴
    • 編寫布局
    • 設定越界滾動
    • 初始化資料和點選事件
    • 建立側滑菜單和點選菜單事件
    • 監聽拖拽,更新UI
    • 監聽觸摸修改背景
  • Github
  • 完事

前言

聽公司開發說,IOS的拖拽排序清單竟然是自帶的控件。。。這也太省事了。。。

下圖是IOS的添加小元件頁面:

android 仿IOS添加小元件的拖拽排序清單,使用SwipeRecyclerView前言幹活Github完事

下圖是我最終的仿造品:

android 仿IOS添加小元件的拖拽排序清單,使用SwipeRecyclerView前言幹活Github完事

下面是操作動圖:

android 仿IOS添加小元件的拖拽排序清單,使用SwipeRecyclerView前言幹活Github完事

幹活

找到合适的輪子

清單拖拽排序并不難做,用ItemTouchHelper和ItemTouchHelper.Callbck就比較好的解決,但是要加上側滑顯示菜單就要多點事情了,這時候找個合适的輪子能省事不少,也能少走一些坑。下面是我找到的一些參考内容:

@minwenping ---- RecyclerView的item拖動排序效果實作和它的ItemTouchHelper詳解

@h6ah4i ---- android-advancedrecyclerview

@yanzhenjie ---- SwipeRecyclerView

有興趣的朋友可以都看一下

我最後使用的是 @yanzhenjie ---- SwipeRecyclerView

因為它支援兩種庫

android 仿IOS添加小元件的拖拽排序清單,使用SwipeRecyclerView前言幹活Github完事

添加依賴

這裡是我用到的第三方庫

// 頂部标題欄
    implementation 'com.github.D10NGYANG:DL10TittleBar:1.0.2'
    // 清單控件
    implementation 'com.yanzhenjie.recyclerview:support:1.3.2'
    // 重新整理控件
    implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-14'
    // RecyclerAdapter架構
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46'
    // 控件注解
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
           

在工程的build.gradle中添加:

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
        
    }
}
           

編寫布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical">

    <com.dlong.rep.dltittlebar.DLTittleBar
        android:id="@+id/tittle_bar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:barBackground="@android:color/white"
        app:leftBtnColor="#3478f3"
        app:leftBtnTxt="取消"
        app:leftBtnVisible="true"
        app:right1BtnVisible="false"
        app:right2BtnColor="#3478f3"
        app:right2BtnTxt="完成"
        app:right2BtnVisible="true"
        app:tittleTxt="">

    </com.dlong.rep.dltittlebar.DLTittleBar>

    <com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/sr_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="50dp"
                    android:gravity="center"
                    android:text="添加小元件"
                    android:textColor="@android:color/black"
                    android:textSize="30sp"
                    android:textStyle="bold" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="50dp"
                    android:gravity="center"
                    android:lineSpacingExtra="4sp"
                    android:paddingLeft="30dp"
                    android:paddingRight="30dp"
                    android:text="快速浏覽,及時從喜愛的應用中了解資訊。在下方添加并整理您的小元件。"
                    android:textColor="@android:color/black" />

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:src="#c8c7cc" />

                <com.yanzhenjie.recyclerview.SwipeRecyclerView
                    android:id="@+id/rcv_select"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:src="#c8c7cc" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:gravity="bottom"
                    android:paddingLeft="20dp"
                    android:paddingBottom="5dp"
                    android:text="更多小元件"
                    android:textColor="@android:color/tertiary_text_light"
                    android:textSize="14sp" />

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:src="#c8c7cc" />

                <com.yanzhenjie.recyclerview.SwipeRecyclerView
                    android:id="@+id/rcv_add"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:src="#c8c7cc" />

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="50dp">

                </RelativeLayout>

            </LinearLayout>

        </android.support.v4.widget.NestedScrollView>

    </com.scwang.smartrefresh.layout.SmartRefreshLayout>

</LinearLayout>
           

設定越界滾動

// 初始化越界滾動
        srRefresh.setEnableRefresh(false);//是否啟用下拉重新整理功能
        srRefresh.setEnableLoadMore(false);//是否啟用上拉加載功能
        srRefresh.setEnablePureScrollMode(true);//是否啟用純滾動模式
        srRefresh.setEnableOverScrollBounce(true);//是否啟用越界回彈
        srRefresh.setEnableOverScrollDrag(true);//是否啟用越界拖動(仿蘋果效果)1.0.4
        srRefresh.setEnableNestedScroll(true);//是否啟用嵌套滾動
           

初始化資料和點選事件

// 初始化資料
        selectList.clear();
        for (int i = 0; i < 5; i++) {
            DataBin bin = new DataBin();
            bin.name = "電腦-" + i;
            selectList.add(bin);
        }
        selectAdapter = new SelectAdapter(selectList);
        selectAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
            @Override
            public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
                switch (view.getId()) {
                    case R.id.img_delete:
                        rcvSelect.smoothOpenRightMenu(position);
                        break;
                }
            }
        });

        addList.clear();
        for (int i = 5; i < 20; i++) {
            DataBin bin = new DataBin();
            bin.name = "電腦-" + i;
            addList.add(bin);
        }
        addAdapter = new AddAdapter(addList);
        addAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
            @Override
            public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
                switch (view.getId()) {
                    case R.id.img_add:
                        DataBin bin = addList.get(position);
                        selectList.add(bin);
                        selectAdapter.notifyDataSetChanged();
                        addList.remove(bin);
                        adapter.notifyItemRemoved(position);
                        break;
                }
            }
        });
           

建立側滑菜單和點選菜單事件

/**
     * 菜單建立器。
     */
    private SwipeMenuCreator mSwipeMenuCreator = new SwipeMenuCreator() {
        @Override
        public void onCreateMenu(SwipeMenu swipeLeftMenu, SwipeMenu swipeRightMenu, int position) {
            int width = getResources().getDimensionPixelSize(R.dimen.dp_60);

            // 1. MATCH_PARENT 自适應高度,保持和Item一樣高;
            // 2. 指定具體的高,比如80;
            // 3. WRAP_CONTENT,自身高度,不推薦;
            int height = ViewGroup.LayoutParams.MATCH_PARENT;

            // 添加右側的,如果不添加,則右側不會出現菜單。
            {
                SwipeMenuItem deleteItem = new SwipeMenuItem(MainActivity.this).setBackground(
                        R.drawable.selector_red)
                        .setText("移除")
                        .setTextColor(Color.WHITE)
                        .setWidth(width)
                        .setHeight(height);
                swipeRightMenu.addMenuItem(deleteItem);// 添加一個按鈕到右側側菜單。
            }
        }
    };

    /**
     * RecyclerView的Item的Menu點選監聽。
     */
    private OnItemMenuClickListener mItemMenuClickListener = new OnItemMenuClickListener() {
        @Override
        public void onItemClick(SwipeMenuBridge menuBridge, int position) {
            menuBridge.closeMenu();

            int direction = menuBridge.getDirection(); // 左側還是右側菜單。
            int menuPosition = menuBridge.getPosition(); // 菜單在RecyclerView的Item中的Position。

            if (direction == SwipeRecyclerView.RIGHT_DIRECTION) {
                // 移除
                DataBin bin = selectList.get(position);
                addList.add(bin);
                addAdapter.notifyDataSetChanged();
                selectList.remove(bin);
                selectAdapter.notifyItemRemoved(position);
            }
        }
    };
           

監聽拖拽,更新UI

/**
     * 拖拽監聽
     */
    OnItemMoveListener mItemMoveListener = new OnItemMoveListener() {
        @Override
        public boolean onItemMove(RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetHolder) {
            // 不同的ViewType不能拖拽換位置。
            if (srcHolder.getItemViewType() != targetHolder.getItemViewType()) return false;

            // 真實的Position:通過ViewHolder拿到的position都需要減掉HeadView的數量。
            int fromPosition = srcHolder.getAdapterPosition() - rcvSelect.getHeaderCount();
            int toPosition = targetHolder.getAdapterPosition() - rcvSelect.getHeaderCount();

            Collections.swap(selectList, fromPosition, toPosition);
            selectAdapter.notifyItemMoved(fromPosition, toPosition);
            return true;// 傳回true表示處理了并可以換位置,傳回false表示你沒有處理并不能換位置。
        }

        @Override
        public void onItemDismiss(RecyclerView.ViewHolder srcHolder) {
            // 此方法在Item在側滑删除時被調用。
        }
    };
           

監聽觸摸修改背景

/**
     * 觸摸動作監聽
     */
    private OnItemStateChangedListener mStateChangedListener = new OnItemStateChangedListener() {
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            LinearLayout ll = viewHolder.itemView.findViewById(R.id.ll_item);
            ImageView line = viewHolder.itemView.findViewById(R.id.line_bottom);
            if (actionState == OnItemStateChangedListener.ACTION_STATE_DRAG) {
                // 狀态:正在拖拽。
                srRefresh.setEnableOverScrollBounce(false);//是否啟用越界回彈
                srRefresh.setEnableOverScrollDrag(false);//是否啟用越界拖動(仿蘋果效果)1.0.4
                rcvSelect.setNestedScrollingEnabled(false);
                // 拖拽的時候背景就透明了,這裡我們可以添加一個特殊背景。
                ll.setSelected(true);
                line.setVisibility(View.INVISIBLE);
            } else if (actionState == OnItemStateChangedListener.ACTION_STATE_SWIPE) {
                // 狀态:滑動删除。
            } else if (actionState == OnItemStateChangedListener.ACTION_STATE_IDLE) {
                // 狀态:手指松開。
                srRefresh.setEnableOverScrollBounce(true);//是否啟用越界回彈
                srRefresh.setEnableOverScrollDrag(true);//是否啟用越界拖動(仿蘋果效果)1.0.4
                rcvSelect.setNestedScrollingEnabled(true);
                // 在手松開的時候還原背景。
                ll.setSelected(false);
                line.setVisibility(View.VISIBLE);
            }
        }
    };
           

Github

D10NGYANG/DragRecycleViewTest

完事