Kiba518

Kiba518

沈阳-架构-开发。

Fork me on GitHub

RecyclerView使用详解

使用RecyclerView要引用对应的jar包,但最新版的项目中,不用引用也可以使用。

implementation 'com.android.support:recyclerview-v7:27.1.1'

RecyclerView.Adapter

首先在界面定义一个RecyclerView。

 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView_frist"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true">
​
        </androidx.recyclerview.widget.RecyclerView>
​
    </LinearLayout>

然后定义一个RecyclerView的ItemView的模板,即每行的模板。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">
​
        
        <TextView
            android:id="@+id/item_tttt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text=""
            android:textColor="@color/black" />
​
        <TextView
            android:id="@+id/item_bbbb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text=""
            android:textColor="@color/black" />
​
​
</LinearLayout>

然后在代码中配置RecyclerView的Adapter(适配器)。

 List<Cache_User> list= new ArrayList<Cache_User>();
        for(int i=0; i<10;i++){
            Cache_User user=new Cache_User();
            user.setName("test"+i);
​
            list.add(user);
        }
        binding.recyclerViewfrist.setLayoutManager(new LinearLayoutManager(this.getContext()));//这里用线性显示 类似于listview
        //binding.recyclerViewfrist.setLayoutManager(new GridLayoutManager(this, 2));//这里用线性宫格显示 类似于grid view
        //binding.recyclerViewfrist.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));//这里用线性宫格显示 类似于瀑布流 
        binding.recyclerViewfrist.setAdapter(new NormalRecyclerViewAdapter(this.getContext(),list));

如上代码,首先定义一个对象的集合,然后设置RecyclerView的排列模式为线型纵向(LinearLayout默认是纵向)。

然后编写NormalRecyclerViewAdapter适配器。

首先定义适配器类继承RecyclerView.Adapter。

然后定义构造函数接受两个参数,一个是Activity的Context,一个的列表数据。

因为,列表每次滑动都刷清空数据,所以必须在适配器里把数据进行缓存。

在RecyclerView的每一行创建时,会先触发onCreateViewHolder,我们先在onCreateViewHolder里把每一行使用的模板XML设定一下,使用 LayoutInflater.from(context).inflate(R.layout.recyclerview_frist, parent, false)。然后把返回的view用NormalViewHolder封装一下,将view保存起来。(NormalViewHolder继承ViewHolder)

然后在每一行绑定数据时会触发onBindViewHolder,我们在onBindViewHolder里把他默认提供的入参ViewHolder,转换会NormalViewHolder,这样我们就可以得到这一行的view了,然后通过view.findViewById找到这一行的全部控件,在通过position参数,在数据列表entityList中定位到这一行应该绑定的数据,然后将控件进行赋值。

这样就实现了RecyclerView数据的缓存。

代码如下:

public class NormalRecyclerViewAdapter extends RecyclerView.Adapter {
    private Context context;
    private List<Cache_User> entityList;
​
    public NormalRecyclerViewAdapter (Context context, List<Cache_User> entityList){
        this.context = context;
        this.entityList = entityList;
    }
​
    @NotNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.recyclerview_frist, parent, false);
        NormalViewHolder rh = new NormalViewHolder(view);
        return rh;
    }
​
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onBindViewHolder(@NotNull RecyclerView.ViewHolder holder, int position) {
        Cache_User entity = entityList.get(position);
        View view =  ((NormalViewHolder)holder).itemView;
//        ImageView im = (ImageView) view.findViewById(R.id.imageHeader);
​
        TextView tv = (TextView) view.findViewById(R.id.item_tttt);
        tv.setText(entity.name);
    }
​
    @Override
    public int getItemCount() {
        return entityList.size();
    }
    private class NormalViewHolder  extends RecyclerView.ViewHolder  {
​
        public View itemView;
        public NormalViewHolder(View _itemView) {
            super(_itemView);
            itemView = _itemView;
        }
    }
}

BaseQuickAdapter

BaseQuickAdapter比起RecyclerView.Adapter有一定的代码优化,但还是要一个列表对应一个适配器。

引用BaseQuickAdapter的包,要版本3以上。

implementation "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4"

RecyclerView的使用方式都一样,都是页面先使用RecyclerView,然后在代码中写RecyclerView的配置。

SFragmentAdapter adapter = new SFragmentAdapter(this.getContext(),list);
         binding.recyclerViewS.setLayoutManager(new LinearLayoutManager(this.getContext()));//这里用线性显示 类似于listview
         binding.recyclerViewS.setAdapter(adapter);
         OnItemChildClickListener listener = (listenerAdapter, view, position) -> {
            Cache_User user = list.get(position);
​
            switch (view.getId()) {
                case R.id.btnLook:
                    ((BaseActivity)getActivity()).ShowMessage_Snackbar(root,"fdfd");
                    break;
​
            }
        };
        adapter.addChildClickViewIds(R.id.btnLook);//为行内按钮注册点击事件
        adapter.setOnItemChildClickListener(listener);//注册整个点击事件
 //View加载完成时回调
                        recyclerView_frist.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
                                .OnGlobalLayoutListener() {
                            @Override
                            public void onGlobalLayout() {

                                LoopHelper.loopHandler(()->{
                     Date serverDate = new Date;
                                  SimpleDateFormat df= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                    for (int i = 0; i <layoutManager.getChildCount() ; i++) {
                                        Goods item = goodsList.get(i);//item.hitTime
                                        Date goodsSellDate = new Date();

                                        try {
                                            goodsSellDate = df.parse((item.hitTime));
                                        } catch (ParseException e) {
                                            e.printStackTrace();

                                        }
                                        //
                                        if (serverDate.before(goodsSellDate)) {
                                            View view = layoutManager.findViewByPosition(i);
                                            if (null != view) {
                                                TextView tvd = view.findViewById(R.id.tv_datetime);
                                                long nd = 1000 * 24 * 60 * 60;//每天毫秒数
                                                long nh = 1000 * 60 * 60;//每小时毫秒数
                                                long nm = 1000 * 60;//每分钟毫秒数
                                                long ns = 1000;//每秒钟毫秒数
                                                long diff = goodsSellDate.getTime() - serverDate.getTime(); // 获得两个时间的毫秒时间差异
                                                long day = diff / nd;   // 计算差多少天
                                                long hour = diff % nd / nh; // 计算差多少小时
                                                long min = diff % nd % nh / nm;  // 计算差多少分钟
                                                long sec = diff % nd % nh % nm / ns;  // 计算差多少秒
                                                String dateStr = day + "天" + hour + "小时" + min + "分钟" + sec + "秒";
                                                tvd.setText("销售 " + dateStr);
                                            }
                                        } else {

                                        }


                                    }

                                },1000);

                                //OnGlobalLayoutListener可能会被多次触发,所以完成了需求后需要移除OnGlobalLayoutListener
                                recyclerView_frist.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                            }
                        });

  

如上代码所示,使用了BaseQuickAdapter的子类SFragmentAdapter,进行配置RecyclerView。

配置完成后,又使用BaseQuickAdapter的子类的对象实现行内按钮的点击事件。

然后编写BaseQuickAdapter的子类SFragmentAdapter。

public class SFragmentAdapter extends BaseQuickAdapter<Cache_User, BaseViewHolder> {
    private Context context;
​
    public SFragmentAdapter(@Nullable Context _context, @Nullable List<Cache_User>  data) {
        super(R.layout.recyclerview_surveyfragment, data);
        this.context=_context;
    }
    @Override
    protected void convert(BaseViewHolder helper, Cache_User item) {
​
        helper.setText(R.id.name,"姓名:"+item.name);
        helper.setText(R.id.loginName,"登录名:"+item.loginName);
        helper.setText(R.id.realId,"真实ID:"+item.realId);
        helper.setText(R.id.id,"ID:"+item.id);
    }
}

如上所示,在BaseQuickAdapter的子类中,我们只需要重写一个convert方法就可以了。

BaseViewHolder提供两个参数,一个是ViewHolder,他返回的是BaseViewHolder类型的ViewHolder,一个是当前行的实体。然后什么使用BaseViewHolder提供的函数,对当前行内的控件赋值,就实现了数据缓存。

代码相对比RecyclerView.Adapter简单一点。

PS1:默认的Style设置为带的Bridge的【Theme.MaterialComponents.Light.NoActionBar.Bridge】时,按钮样式才受自定义控制。

PS2:this表示类的实例,通常Activity内部this就是Activity本身的实例,但如果是方法内部this就会表示这个方法所有类的实例,比如在Activity内部做一个Http请求,那么Http请求的回调函数中,this就是不是Activity的实例了,而如此此时需要跳转页面,而Intent的入参需要Activity,那么就需要使用Activity.this来获取实例

<style name="Theme.Survey" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">

----------------------------------------------------------------------------------------------------

注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

 

 

posted @ 2021-09-09 11:35  kiba518  阅读(1307)  评论(0编辑  收藏  举报