1. 程式人生 > >RecycleView實現長按多選全選刪除功能

RecycleView實現長按多選全選刪除功能

一、功能:

recycleView橫向列表,實現item新增,長按選擇,全選,全不選的刪除,滑動刪除功能。

用realm構建資料庫儲存列表資料。用FloatingActionButton 作為新增按鈕。

思路:

activity頁面最下面新增一個帶有刪除tab的view,當長按item的時候,view顯示出來。

adapter的itemview裡面,帶有一個checkbox,長按item的時候,checkbox顯示出來。

adapter裡面新增一個是否刪除模式的boolen型判斷物件inDeletionMode,和一個Set<Users> selectedUsers被選中刪除列表。

長按item的時候,inDeletionMode設定為true,並且notifydatasetChanged,更新Bindviewholder的檢視,讓checkbox顯示出來,

刪除模式的時候,checkbox為true的時候,將該位置的user新增到設selectedUsers裡面。

點選全選、全不選的時候,更新adapter裡面的selectedUsers物件,並且更新檢視顯示。

realm的使用參考:realm詳解

效果圖:

效果圖

二、實現

1、activity

xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>


    <android.support.design.widget.FloatingActionButton
        android:id="@+id/btn_floating"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_gravity="right|bottom"
        android:layout_margin="16dp"
        android:src="@mipmap/add_user"
        android:backgroundTint="@color/light_gray"
        app:rippleColor="@color/login_line_color"/>

    <LinearLayout
        android:id="@+id/ll_delete"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:background="@color/white"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="@color/color_text_hint"/>

        <com.landicorp.dependencelibrary.widget.TabView
            android:id="@+id/tab_delete"
            android:layout_width="40dp"
            android:layout_height="wrap_content"
            android:paddingBottom="16dp"
            app:color="@color/color_text_normal"
            app:icon="@mipmap/delete"
            app:text="刪除"
            app:text_size="12sp"/>

    </LinearLayout>

</RelativeLayout>

activity:


/**
 * 使用者列表,可長按刪除,滑動刪除,新增使用者
 */

public class VIPActivity extends BusinessActivity implements View.OnClickListener, UserAdapter.onItemClickListener {

    private RecyclerView recyclerView;
    private FloatingActionButton btnFloating;
    private TabView tabDelete;
    private LinearLayout llDelete;

    private RealmResults<Users> usersList;
    private UserAdapter adapter;
    Realm realm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vip);
        realm = Realm.getDefaultInstance();
        initView();
        setTitle("VIP列表");
        //全選按鈕設定監聽
        getRlTextAheadView().setOnClickListener(this);
    }

    //初始化view,recycleView新增介面卡,繫結ItemTouchHelper
    private void initView() {
        usersList = realm.where(Users.class).findAll();
        adapter = new UserAdapter();
        adapter.setUsersList(usersList);
        adapter.setListener(this);
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        btnFloating = (FloatingActionButton) findViewById(R.id.btn_floating);
        tabDelete = (TabView) findViewById(R.id.tab_delete);
        llDelete = (LinearLayout) findViewById(R.id.ll_delete);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        recyclerView.setAdapter(adapter);
        //將touchhelper和recycleview繫結,實現滑動刪除,但是不能實現上下拖拽item,因為realm不支援Collection.swap方式
        //這裡自定義了一個callback實現了ItemTouchHelper.Callback介面方法,傳入adapter物件相應滑動刪除事件
        ItemTouchHelper.Callback callback = new MyItemHelpCallBack(adapter);
        ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
        touchHelper.attachToRecyclerView(recyclerView);

        btnFloating.setOnClickListener(this);
        tabDelete.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_floating:
                addUser();
                break;
            case R.id.tab_delete:
                if (llDelete.isShown()) {
                    deleteUsers();
                    hideAhead();
                    llDelete.setVisibility(View.GONE);
                    btnFloating.setVisibility(View.VISIBLE);
                    adapter.setInDeletionMode(false);
                }
                break;
            case R.id.rl_head_text:
                seletAllOrNot();
                break;
            default:
                break;
        }
    }

    //新增物件
    public void addUser() {
        DialogUtils.showAddUserDialog(this, "新增使用者", new AddUserDialog.onAddUserListener() {
            @Override
            public void addUser(String name, String cardNo) {
                realm.beginTransaction();
                Users user = realm.createObject(Users.class);
                user.setName(name);
                user.setCardNo(cardNo);
                realm.commitTransaction();
            }
        });
    }

    //刪除選中物件
    public void deleteUsers() {
        Set<Users> selectSet = adapter.getSelectSet();
        realm.beginTransaction();
        Iterator<Users> iterator = selectSet.iterator();
        while (iterator.hasNext()) {
            Users user = iterator.next();
            if (usersList.contains(user)) {
                user.deleteFromRealm();
            }
        }
        realm.commitTransaction();
    }

    //點選全選,全不選,狀態切換
    private void seletAllOrNot() {
        if (adapter.getSelectSet().size() < usersList.size()) {
            Set<Users> selectSet = adapter.getSelectSet();
            for (int i = 0; i < usersList.size(); i++) {
                selectSet.add(usersList.get(i));
            }
            adapter.setSelectSet(selectSet);
            adapter.notifyDataSetChanged();
            setAheadText("全不選");
        } else {
            adapter.setSelectSet(new HashSet<Users>());
            adapter.notifyDataSetChanged();
            setAheadText("全選");
        }
    }

    @Override
    public void onItemClick(final Users user) {
       //listitem 點選事件
    }

    //長按item,隱藏floatingbtn,顯示全選按鈕,
    //通知adapter變為刪除選擇模式,將當前選中的item的checkbox設定為true
    @Override
    public void onItemLongCick(Users user) {
        if (!llDelete.isShown()) {
            showTextAhead();
            setAheadText("全選");
            llDelete.setVisibility(View.VISIBLE);
            btnFloating.setVisibility(View.GONE);
            Set<Users> selectSet = new HashSet<>();
            selectSet.add(user);
            adapter.setSelectSet(selectSet);
            adapter.setInDeletionMode(true);
        }
    }


    //滑動刪除item
    @Override
    public void onSwipeToDeleteUser(int position) {
        if (usersList.size() >= position) {
            realm.beginTransaction();
            usersList.get(position).deleteFromRealm();
            realm.commitTransaction();

            adapter.notifyDataSetChanged();
        }
    }

    //activity監聽到adapter選擇了全部的item,全選變成全不選
    @Override
    public void selectedAll() {
        setAheadText("全不選");
    }

    //點選返回按鈕,如果是刪除狀態,取消刪除
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (llDelete.isShown()) {
            llDelete.setVisibility(View.GONE);
            btnFloating.setVisibility(View.VISIBLE);
            hideAhead();
            adapter.setInDeletionMode(false);
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

    //關閉realm,防止記憶體洩漏
    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }
}

2、adapter

item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:background="@color/white"
    android:gravity="center_vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp">


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


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1.8"
            android:gravity="center_vertical"
            android:padding="5dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="姓名:"
                android:textColor="@color/color_text_normal"
                android:textSize="14sp"/>

            <TextView
                android:id="@+id/tv_name"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textColor="@color/color_text_normal"
                android:textSize="14sp"/>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1.2"
            android:paddingLeft="5dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="卡號:"
                android:textColor="@color/color_text_hint"
                android:textSize="12sp"/>

            <TextView
                android:id="@+id/tv_cardNo"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textColor="@color/color_text_hint"
                android:textSize="12sp"/>

        </LinearLayout>
    </LinearLayout>

    <CheckBox
        android:id="@+id/checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginTop="10dp"
        android:visibility="gone"/>
</RelativeLayout>

adapter:

/**
 * 使用者列表介面卡
 */

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> implements View.OnClickListener
        , View.OnLongClickListener {

    private RealmResults<Users> usersList;

    private onItemClickListener listener;

    //設定顯示的資料
    public void setUsersList(RealmResults<Users> usersList) {
        this.usersList = usersList;
    }

    //設定監聽器
    public void setListener(onItemClickListener listener) {
        this.listener = listener;
    }

    //是否刪除模式
    private boolean inDeletionMode = false;

    //設定是否為刪除模式,改變繫結檢視
    public void setInDeletionMode(boolean inDeletionMode) {
        this.inDeletionMode = inDeletionMode;
        notifyDataSetChanged();
    }

    //選中要刪除使用者
    private Set<Users> selectSet = new HashSet<>();

    /**
     * 獲取選中要刪除的列表
     *
     * @return
     */
    public Set<Users> getSelectSet() {
        return selectSet;
    }

    public void setSelectSet(Set<Users> selectSet) {
        this.selectSet = selectSet;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        //這裡呼叫realm的isValid方法,判斷當前資料是否可用,防止出現數據被刪除仍然使用導致崩潰
        if (usersList.get(position).isValid()) {

            holder.tvName.setText(usersList.get(position).getName());
            holder.tvCardNo.setText(usersList.get(position).getCardNo());
            //刪除模式,checkbox顯示,否則不顯示
            holder.checkbox.setVisibility(inDeletionMode ? View.VISIBLE : View.GONE);


            if (inDeletionMode) {
                holder.rootView.setOnClickListener(null);
                holder.rootView.setOnLongClickListener(null);

                //設定當前item的checkbox是否為選中狀態
                //item長按刪除的時候,activity設定了當前長按的item物件儲存在selectset裡面了
                holder.checkbox.setChecked(selectSet.contains(usersList.get(position)));
                holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        if (isChecked) {
                            selectSet.add(usersList.get(position));
                        } else {
                            selectSet.remove(usersList.get(position));
                        }

                        //全部選中,通知activity “全選” 變成 “全不選”
                        if (selectSet.size() == usersList.size()) {
                            listener.selectedAll();
                        }
                    }
                });
            } else {
                holder.checkbox.setOnCheckedChangeListener(null);
                holder.rootView.setOnClickListener(this);
                holder.rootView.setOnLongClickListener(this);
            }

            holder.itemView.setTag(usersList.get(position));
        }
    }

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

    @Override
    public void onClick(View v) {
        Users user = (Users) v.getTag();
        if (null != user && listener != null) {
            listener.onItemClick(user);
        }
    }

    @Override
    public boolean onLongClick(View v) {
        Users user = (Users) v.getTag();
        if (null != user && listener != null) {
            listener.onItemLongCick(user);
        }
        return true;
    }

    public void swapData(int from, int to) {
        //This method is not supported by 'RealmResults' or 'OrderedRealmCollectionSnapshot'.
        Collections.swap(usersList, from, to);
    }

    public void swipeDelete(int position) {
        if (null != listener) {
            listener.onSwipeToDeleteUser(position);
        }
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        public View rootView;
        public TextView tvName;
        public TextView tvCardNo;
        public CheckBox checkbox;

        public ViewHolder(View rootView) {
            super(rootView);
            this.rootView = rootView;
            this.tvName = (TextView) rootView.findViewById(R.id.tv_name);
            this.tvCardNo = (TextView) rootView.findViewById(R.id.tv_cardNo);
            this.checkbox = (CheckBox) rootView.findViewById(R.id.checkbox);
        }

    }

    public interface onItemClickListener {
        void onItemClick(Users user);

        void onItemLongCick(Users user);

        void onSwipeToDeleteUser(int position);

        void selectedAll();
    }

}

注:realm給recycleview提供了官方的介面卡,很好用,只不過我這次沒有用

Realm官方RecycleView介面卡demo

3、自定義ItemTouchHelperCallBack

/**
 * 自定義ItemTouchHelper.Callback
 */

public class MyItemHelpCallBack extends ItemTouchHelper.Callback {

    private UserAdapter adapter;

    public MyItemHelpCallBack(UserAdapter adapter) {
        this.adapter = adapter;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //允許上下的拖動
        int swipeFlags = ItemTouchHelper.LEFT; //只允許從右向左側滑
        return makeMovementFlags(dragFlags, swipeFlags);

    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        //This method is not supported by 'RealmResults' or 'OrderedRealmCollectionSnapshot'.
        //realm 不支援 Collections.swap()方法
        //        adapter.swapData(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        adapter.swipeDelete(viewHolder.getAdapterPosition());
    }
}