OnItemClickListener接口回調實現RecyclerView點擊事件


1、技術概述

使用ReclclerView列出賬單分類,使用OnItemClickListener接口回調的方法實現在RecyclerView.Adapter外實現對RecyclerView的子項的點擊交互事件。技術難點在於在適配器中定義接口,在具體引用的Activity中調用接口具體實現。

2、技術詳述

(1)要使用RecyclerView這個控件,首先得在項目的build.gradle中添加相應的依賴庫。

  • 打開app/build.gradle文件,在dependencies閉包中添加以下內容:
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    testCompile 'junit:junit:4.12'
}
  • 添加完成后記得點擊Sync Now進行庫的同步。

(2)安裝完依賴后,我們到布局文件中引入ReclclerView。外面包裹的容器是要RelativeLayout或者LinearLayout看你是要豎着顯示每個Item還是橫着顯示。

  • RelativeLayout是列表式的豎着顯示:
   ······
<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

</RelativeLayout>
   ······
  • 具體效果圖:

  • LinearLayout為橫向顯示,加上GridLayout可以使Item呈網格式布局。
   ······
<GridLayout
            android:id="@+id/viewpager_item"
            android:layout_width="match_parent"
            android:layout_height="130dp">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

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

            </LinearLayout>
</GridLayout>
   ······
  • 具體效果圖:

(3)在layout文件中引入ReclclerView后,還需要增加一個xml布局文件,用以定義每個Item要顯示的內容。具體如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="50dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/cardview_light_background">

        <TextView
            android:id="@+id/category_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dp"
            android:textColor="@color/cardview_dark_background" />

    </RelativeLayout>
</LinearLayout>
  • 這邊僅定義了一個TextView用於顯示賬單分類的名稱,大家可以根據需求自行修改。

(4)准備完布局文件,我們需要為RecyclerView准備一個適配器,新建一個類CategoryAdapter,讓這個適配器繼承自ReclclewView.Adapter,並將泛型指定為CategoeyAdapter.ViewHolder。

  • 在《第一行代碼》中RecyclerView中的點擊事件是直接在適配器中實現的,這很顯然不能滿足我們的要求,所以我們在適配器中定義OnItemClickListener接口,然后在要引用適配器的Activity中具體實現該接口,以達到我們所要的RecyclerView的點擊交互效果。具體適配器代碼如下:
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder> {
    private List<Category> mCategoryList;

    //定義OnItemClickListener接口
    public interface OnItemClickListener {
        void onClick(int position);
    }

    public OnItemClickListener listener;

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView categoryName;

        public ViewHolder(View view) {
            super(view);
            categoryName = (TextView) view.findViewById(R.id.category_name);
        }
    }

    public CategoryAdapter(List<Category> mCList) {
        mCategoryList = mCList;
    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Category category = mCategoryList.get(position);
        holder.categoryName.setText(category.getCategory_name());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onClick(position);
                }
            }
        });
    }

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

}

(5)最后,我們在具體的Activity中引入適配器。具體代碼及釋義如下:

public class CategoryEditActivity extends AppCompatActivity implements View.OnClickListener {
    ······
    public CategoryChooseAdapter categoryChooseAdapter;
    public RecyclerView recycleView;
    ······
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ······
    recycleView = (RecyclerView) findViewById(R.id.reclcler_view);

    //初始化數據,裝入ReclclerView中
    initCategory();
    }
    
    //具體實現RecyclerView的Item點擊事件
    public void setCategoryChooseAdapter () {
        //在這邊實現具體的Item交互事件,點擊事件交互的內容可以自行定義
        categoryChooseAdapter.setOnItemClickListener(new CategoryChooseAdapter.OnItemClickListener() {
            @Override
            public void onClick(int position) {
                ······
                //這邊我使用MaterialDialog來實現點擊一個Item后,出現對話框用以修改分類信息
                new MaterialDialog.Builder(CategoryEditActivity.this)
                        .title("修改分類")
                        .canceledOnTouchOutside(false)
                        .input(category_name1, "", new MaterialDialog.InputCallback() {
                            @Override
                            public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {

                            }
                        })
                        .positiveText("確認修改")
                        .negativeText("取消")
                        .neutralText("刪除該分類")
                        .onPositive(new MaterialDialog.SingleButtonCallback() {
                            @Override
                            public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                //修改分類
                                ······
                                Toast.makeText(CategoryEditActivity.this, "修改成功!", Toast.LENGTH_SHORT).show();
                            }
                        })
                        .onNeutral(new MaterialDialog.SingleButtonCallback() {
                            @Override
                            public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                ······
                                //刪除分類
                                Toast.makeText(CategoryEditActivity.this, "該分類已成功刪除!", Toast.LENGTH_SHORT).show();
                            
                        })
                        .onNegative(new MaterialDialog.SingleButtonCallback() {
                            @Override
                            public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                //取消
                                dialog.dismiss();
                                dialog = null;
                            }
                        })
                        .show();
            }
        });
    }

    private void initCategory() {
        CategoryDAO categoryDAO = new CategoryDAOImpl();
        categoryList = categoryDAO.listCategory();
        //從數據庫按需取出分類名稱,裝入categoryList中
        ······
        categoryChooseAdapter = new CategoryChooseAdapter(categoryList);  //將數據裝入RecycerView適配器中
        categoryChooseAdapter.notifyItemRangeChanged(0, categoryList.size());  //當新添或者刪除某個Item時,能夠即時刷新數據
        recycleView.setAdapter(categoryChooseAdapter); //完成適配器設置

        setCategoryChooseAdapter();  //實現每一個Item點擊事件
    }
}
  • 具體效果圖:

3、技術使用中遇到的問題和解決過程

 RecyclerView並沒有提供類似於setOnItemClickListener這樣的注冊監聽器方法,而是需要我們給子項具體的View去注冊點擊事件。而在《第一行代碼》中實現RecyclerView點擊事件是在Adapter中的onCreateViewHolder()方法中注冊點擊事件,使用這種方法的話,當我們想要的點擊事件復雜一點或者需要使用具體引入的Activity中的一些數據時,就沒辦法滿足。所以開始找尋能夠在適配器之外實現點擊事件的方法。
 經過一番搜尋,發現可以通過接口回調的方式實現外部定義點擊事件。通過在RecyclerView的適配器中定義OnItemClickListener接口,再在Activity中調用接口,具體實現以解決自定義點擊子項交互的問題。
 使用RecyclerView時如果修改了某項子項頁面數據卻沒有即時刷新的話,可調用RecyclerView中的notifyItemRangeChanged()方法,再重新設置適配器setAdapter(),來實現數據的實時更新。

    ······
    categoryChooseAdapter = new CategoryChooseAdapter(categoryList);  //將數據裝入RecycerView適配器中
    categoryChooseAdapter.notifyItemRangeChanged(0, categoryList.size());  //當修改或者刪除某個Item時,能夠即時刷新數據
    recycleView.setAdapter(categoryChooseAdapter); //完成適配器設置

4、總結

《第一行代碼》只是為你的Android開發打下一定的基礎,對Android開發的一些基礎知識進行較為詳細的介紹。而要想做好Android開發,單單靠學完《第一行代碼》還是不夠的,還需要我們在實際開發時不斷地去查找資料,學習更多的拓展知識。

5、參考文獻、參考博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM