Saturday, September 15, 2018

Android RecyclerView Swipe To Delete And Undo

Trong hướng dẫn này, chúng tôi sẽ thảo luận về và thực hiện các Swipe để xóa bỏ tính năng trên RecyclerView trong ứng dụng Android của chúng tôi.

Android Swipe To Delete

Swipe để xóa các tính năng thường được sử dụng để xóa các hàng từ một RecyclerView.

Để thực hiện kéo mạnh để xóa các tính năng, chúng ta cần phải sử dụng các lớp học hữu ích ItemTouchHelper.

ItemTouchHelper.Callback


Để sử dụng lớp ItemTouchHelper, chúng ta cần phải thực hiện các ItemTouchHelper.Callback.

Lớp ItemTouchHelper.Callback được sử dụng chủ yếu cho kéo và thả và vuốt để xóa các hành vi.

Trong hướng dẫn này, chúng tôi sẽ gắn bó với swipe để xóa chỉ.

Khuôn khổ Android cung cấp cho chúng tôi một thực hiện cơ bản của ItemTouchHelper.CallbackSimpleCallback.
Chúng tôi sẽ tạo riêng của chúng tôi thực hiện các Swipe để xóa các tính năng.
Sau đây là những phương pháp chính cần phải được ghi đè trong lớp học của chúng tôi:

getMovementFlags-ở đây chúng tôi thiết lập sự chỉ đạo của swipe. Chúng tôi trở lại cờ hướng trong một makeMovementFlags phương pháp tĩnh.

onMove-điều này được sử dụng để kéo và thả. Nếu không cần thiết, trở lại sai ở đây.
onSwiped-điều này được kích hoạt khi hành động kéo mạnh được phát hiện.
Một swipe hoàn toàn đi toàn bộ chiều rộng của màn hình. Để thiết lập xem xét một swipe một phần như một swipe, chúng ta cần để ghi đè các phương pháp sau đây:

getSwipeThreshold-ở đây chúng ta trở về giá trị nổi. Ví dụ 0.5f có nghĩa là một swipe 50 phần trăm trên dòng RecyclerView sẽ được coi như là một swipe.

onChildDraw-ở đây chúng tôi sẽ tạo xem tuỳ chỉnh của chúng tôi cho thấy rằng swipe đang xảy ra.

Trong phần tiếp theo, chúng ta sẽ sáng tạo của chúng tôi ứng dụng android với một RecyclerView có chứa Swipe để bỏ tính năng. Chúng tôi sẽ cung cấp một Snackbar với các tùy chọn lùi lại.

Thêm phụ thuộc sau đây trong các ứng dụng build.gradle:

implementation 'com.android.support:design:28.0.0-rc01'

Mã cho bố trí activity_main.xml được đưa ra dưới đây:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
 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:id="@+id/coordinatorLayout"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager" />


    </RelativeLayout>

</android.support.design.widget.CoordinatorLayout>

Tạo class SwipeToDeleteCallback.java kế thừa từ ItemTouchHelper.Callback


 package com.journaldev.androidrecyclerviewswipetodelete; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; abstract public class SwipeToDeleteCallback extends ItemTouchHelper.Callback { Context mContext; private Paint mClearPaint; private ColorDrawable mBackground; private int backgroundColor; private Drawable deleteDrawable; private int intrinsicWidth; private int intrinsicHeight; SwipeToDeleteCallback(Context context) { mContext = context; mBackground = new ColorDrawable(); backgroundColor = Color.parseColor("#b80f0a"); mClearPaint = new Paint(); mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); deleteDrawable = ContextCompat.getDrawable(mContext, R.drawable.ic_delete); intrinsicWidth = deleteDrawable.getIntrinsicWidth(); intrinsicHeight = deleteDrawable.getIntrinsicHeight(); } @Override public int getMovementFlags(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder) { return makeMovementFlags(0, ItemTouchHelper.LEFT); } @Override public boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull RecyclerView.ViewHolder viewHolder1) { return false; } @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); View itemView = viewHolder.itemView; int itemHeight = itemView.getHeight(); boolean isCancelled = dX == 0 && !isCurrentlyActive; if (isCancelled) { clearCanvas(c, itemView.getRight() + dX,
(float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom()); super.onChildDraw(c, recyclerView, viewHolder, dX,
dY, actionState, isCurrentlyActive); return; } mBackground.setColor(backgroundColor); mBackground.setBounds(itemView.getRight() + (int) dX,
itemView.getTop(), itemView.getRight(), itemView.getBottom()); mBackground.draw(c); int deleteIconTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2; int deleteIconMargin = (itemHeight - intrinsicHeight) / 2; int deleteIconLeft = itemView.getRight() - deleteIconMargin - intrinsicWidth; int deleteIconRight = itemView.getRight() - deleteIconMargin; int deleteIconBottom = deleteIconTop + intrinsicHeight; deleteDrawable.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom); deleteDrawable.draw(c); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } private void clearCanvas(Canvas c, Float left, Float top, Float right, Float bottom) { c.drawRect(left, top, right, bottom, mClearPaint); } @Override public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { return 0.7f; } }

Lớp học trừu tượng vì chúng tôi chưa triển khai phương pháp onSwipe. Chúng ta sẽ làm điều đó trong lớp MainActivity.java.


Bên trong phương thức onChildDraw, chúng ta kiểm tra xem thao tác vuốt có được thực hiện hay không bằng cách sử dụng boolean isCancelled. Dựa trên đó, chúng tôi tạo chế độ xem có biểu tượng xóa. Chúng tôi đã đặt ngưỡng Vuốt thành 0,7. Điều đó có nghĩa là nếu hàng được vuốt ít hơn 70%, phương pháp onSwipe sẽ không được kích hoạt. Mã cho lớp MainActivity.java được đưa ra dưới đây


package com.journaldev.androidrecyclerviewswipetodelete;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.View;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {


    RecyclerView recyclerView;
    RecyclerViewAdapter mAdapter;
    ArrayList<String> stringArrayList = new ArrayList<>();
    CoordinatorLayout coordinatorLayout;

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

        recyclerView = findViewById(R.id.recyclerView);
        coordinatorLayout = findViewById(R.id.coordinatorLayout);

        populateRecyclerView();
        enableSwipeToDeleteAndUndo();


    }

    private void populateRecyclerView() {
        stringArrayList.add("Item 1");
        stringArrayList.add("Item 2");
        stringArrayList.add("Item 3");
        stringArrayList.add("Item 4");
        stringArrayList.add("Item 5");
        stringArrayList.add("Item 6");
        stringArrayList.add("Item 7");
        stringArrayList.add("Item 8");
        stringArrayList.add("Item 9");
        stringArrayList.add("Item 10");

        mAdapter = new RecyclerViewAdapter(stringArrayList);
        recyclerView.setAdapter(mAdapter);


    }

    private void enableSwipeToDeleteAndUndo() {
        SwipeToDeleteCallback swipeToDeleteCallback = new SwipeToDeleteCallback(this) {
            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {

                
                final int position = viewHolder.getAdapterPosition();
                final String item = mAdapter.getData().get(position);

                mAdapter.removeItem(position);


                Snackbar snackbar = Snackbar
                        .make(coordinatorLayout, "Item was removed from the list.", Snackbar.LENGTH_LONG);
                snackbar.setAction("UNDO", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        
                        mAdapter.restoreItem(item, position);
                        recyclerView.scrollToPosition(position);
                    }
                });

                snackbar.setActionTextColor(Color.YELLOW);
                snackbar.show();

            }
        };

        ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeToDeleteCallback);
        itemTouchhelper.attachToRecyclerView(recyclerView);
    }


}
Để thiết lập ItemTouchHelper vào RecyclerView, phương thức attachToRecyclerView được sử dụng. Khi nhấp vào hành động Snackbar, chúng tôi khôi phục mục trong RecyclerView bằng phương thức restoreItem. Phương thức restoreItem được định nghĩa trong lớp RecyclerViewAdapter. scrollToPosition cuộn RecyclerView đến vị trí được chỉ định. Điều này chủ yếu được sử dụng khi một mục được chèn vào đầu RecyclerView.
Mã cho cardview_row.xml được đưa ra dưới đây:



<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="64dp"
    android:layout_margin="8dp"
    card_view:cardCornerRadius="0dp"
    card_view:cardElevation="2dp">


    <RelativeLayout
        android:id="@+id/relativeLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="8dp"
        android:paddingLeft="8dp"
        android:paddingRight="8dp">


        <TextView
            android:id="@+id/txtTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:text="Item 1"
            android:textAppearance="@style/TextAppearance.Compat.Notification.Title" />
    </RelativeLayout>

</android.support.v7.widget.CardView>



Mã cho lớp RecyclerViewAdapter.java được đưa ra dưới đây:


package com.journaldev.androidrecyclerviewswipetodelete;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter {

    private ArrayList data;

    public class MyViewHolder extends RecyclerView.ViewHolder {

        private TextView mTitle;
        RelativeLayout relativeLayout;

        public MyViewHolder(View itemView) {
            super(itemView);

            mTitle = itemView.findViewById(R.id.txtTitle);
        }
    }

    public RecyclerViewAdapter(ArrayList data) {
        this.data = data;
    }

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

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.mTitle.setText(data.get(position));
    }

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


    public void removeItem(int position) {
        data.remove(position);
        notifyItemRemoved(position);
    }

    public void restoreItem(String item, int position) {
        data.add(position, item);
        notifyItemInserted(position);
    }

    public ArrayList getData() {
        return data;
    }
}




No comments:

Post a Comment