欢迎来到张钰婷的博客

待凛冬散去,雪融草原,相信一定有新的相逢将温暖延续。

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、参考文献、参考博客

posted on 2020-06-24 14:44  Chloe_YT  阅读(1294)  评论(0编辑  收藏  举报

导航