一、RecycleView的基本使用


RecycleView同ListView一样在APP页面中以列表的形式显示元素,由于提供数据的方式有很多种list,array,map或者set等,但是最终都需要将这些数据源,以统一的样式显示出来。因此在RecycleView(ListView)的使用中,有RecycleView负责显示,Adpter负责对数据进行适配操作,数据源(一般是List)部分。


1.1 gradle倒包


compile 'com.android.support:recyclerview-v7:25.2.0'


1.2 布局控件


在Activity的activity_main.xml布局文件中添加RecycleView控件


<?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="match_parent" 


 android:orientation="vertical"> 





 <android.support.v7.widget.RecyclerView 


 android:id="@+id/id_recycler_view" 


 android:layout_width="match_parent" 


 android:layout_height="match_parent"> 





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


</LinearLayout>


为这个RecycleView创建一个item布局文件item_recycleview.xml,并为它添加简单的元素TextView,代码如下


<?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="60dp"



android:gravity="center_vertical">





<TextView



android:id="@+id/recycle_textview"



android:layout_width="match_parent"



android:layout_height="50dp"



android:gravity="center"



android:textSize="20sp"/>



</LinearLayout>


1.3 Adater代码和Activity代码的编写


RecyclerView.Adapter适配器TestRecycleViewAdapter,在新建的Adapter中需要完成三个重要的操作:


1.实现一个RecycleView.ViewHolder,该ViewHolder主要用来绑定创建的item_recycleview.xml布局文件中的控件元素。


2.重写父类的onCreateViewHolder函数,该函数主要用来创建刚定义的ViewHolder的对象,可以用来显示Item元素。


3.重写父类的onBindViewHolder函数,在函数中可以设置每个Item项特有的参数信息。


public        classTestRecycleViewAdapterextendsRecyclerView       .       Adapter<TestRecycleViewAdapter       .       ViewHolderA>        {


privateContext        mContext;


privateList       <       String       > mList;





 public        TestRecycleViewAdapter       (       Context        context,        List       <       String       > list) {


 mContext = context;


 mList = list;


 }





//创建每个显示的Item元素


@Override


 public        ViewHolderA        onCreateViewHolder(       ViewGroup        parent, int viewType) {


//此处动态加载ViewHolder的布局文件并返回holder


View        view =        LayoutInflater       .from(mContext).inflate(       R       .layout.recycleview_item, parent,        false       );


ViewHolderA        holderA =        newViewHolderA       (view);


return        holderA;


 }





//设置每个显示的Item元素的独特的参数


@Override


 public void onBindViewHolder(       ViewHolderA        holder, int position) {


//此处设置Item中view的数据


 holder.mTextView.setText(mList.get(position));


 }





@Override


 public int getItemCount() {


//生成的item的数量


return        mList.size();


 }





//RecyclerView中每个Item的ViewHolder,以及item内部布局控件进行id绑定


classViewHolderAextendsRecyclerView       .       ViewHolder       {





TextView        mTextView;


 public        ViewHolderA       (       View        itemView) {


super       (itemView);


 mTextView = (       TextView       ) itemView.findViewById(       R       .id.recycle_textview);


 }


 }


}


在Activity中使用的代码


public class MainActivity extends AppCompatActivity {


 private List<String> list;        //数据源


 @Override


 protected void onCreate(Bundle savedInstanceState) {


 super.onCreate(savedInstanceState);


 setContentView(R.layout.activity_main);





 RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.activity_main_recycle_view);


 mRecyclerView.setLayoutManager(new LinearLayoutManager(this));


 initData();


//实例化adapter,并传输数据给adapter


 TestRecycleViewAdapter adapter = new TestRecycleViewAdapter(getApplicationContext(), list);


 mRecyclerView.setAdapter(adapter);


 }





 /**


 * 添加数据


 * */


 private void initData() {


 list = new ArrayList<>();


 for (int i = 0; i < 50; i++) {


 list.add("item" + i);


 }


 }


}


二、RecycleView的不同风格和布局的显示


可以参考链接: https://www.jianshu.com/p/c35ca003654d


三、RecycleView的Item点击事件


RecycleView的Item点击事件的处理方式有三种:


3.1 在Adpater中实现


直接在Adapter中的onBindViewHolder()方法中实现点击事件,参考如下代码。


@Override


        public               void               onBindViewHolder       (MyViewHolder viewHolder,        final               int        postion) {





 viewHolder.textView.setText(mDatas.get(postion));


 viewHolder.rootView.setOnClickListener(       new        OnClickListener() {


        @Override


        public               void               onClick       (View arg0) {


        // 点击事件


 Toast.makeText(mContext, postion +        ""       ,        1000       ).show();


 }


 });


 }


这种方式的优点是,可以很方便的实现点击事件,代码不用很复杂;缺点也很明显,就是adapter一般只持有数据源的引用,不能实现很复杂的逻辑处理操作。


3.2 在Activity中实现


1.先在Adapter中定义一个接口。


public               interface        onRecyclerViewItemClick {


        void        onItemClick(View v,        int        position);


 }


2. 在Adapter中定义一个刚才定义的接口变量,并定义一个函数,或者在Adapter的构造函数中接受接口的引用。


private        onRecyclerViewItemClick mOnRvItemClick;





        public        DemoAdapter(Context ctx, String[] strings, onRecyclerViewItemClick onRvItemClick) {


 mContext = ctx;


        this       .mOnRvItemClick = onRvItemClick;


        this       .strings = strings;


 }


3. 在自定义的ViewHolder中实现onClickListenr接口,并设置onItemClick事件,将点击事件传到自定义的接口上去,最终传到外面的Activity调用者上去。


public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {



@BindView(R.id.textView)



TextView textView;






public ViewHolder(View itemView) {



super (itemView);



ButterKnife.bind( this , itemView);



itemView.setOnClickListener( this );



}






public void setData( int position) {



textView.setText("第" + position + "行");



}



//设置onItemClick事件



@Override



public void onClick(View view) {



if (mOnRvItemClick != null )



mOnRvItemClick.onItemClick(view, getAdapterPosition());



}



}


4.在Activity中实现onItemClick方法


public               class        MainActivity        extends        AppCompatActivity {





 @BindView(R.id.recycler_view)


 RecyclerView mRecyclerView;





 @Override


        protected               void        onCreate(Bundle savedInstanceState) {


        super       .onCreate(savedInstanceState);


 setContentView(R.layout.activity_main);


 ButterKnife.bind(       this       );


 DemoAdapter myAdapter =        new        DemoAdapter(       this       ,        null       ,        new DemoAdapter.onRecyclerViewItemClick() {


 @Override


 public void onItemClick(View v, int position) {


 Snackbar.make(v, "第" + position + "行", Snackbar.LENGTH_SHORT).show();


 }


 }       );


 mRecyclerView.setLayoutManager(       new        LinearLayoutManager(       this       , LinearLayoutManager.VERTICAL,        false       ));


 mRecyclerView.setAdapter(myAdapter);


 }





}


5.为了便于查阅,整体的Adapter的代码如下。


public               class        DemoAdapter        extends        RecyclerView.Adapter<DemoAdapter.ViewHolder> {





        private        onRecyclerViewItemClick mOnRvItemClick;





        private        Context mContext;





 String[] strings;





        public        DemoAdapter(Context ctx, String[] strings, onRecyclerViewItemClick onRvItemClick) {


 mContext = ctx;


        this       .mOnRvItemClick = onRvItemClick;


        this       .strings = strings;


 }





 @Override


        public        ViewHolder onCreateViewHolder(ViewGroup parent,        int        viewType) {


 View view = LayoutInflater.from(mContext).inflate(R.layout.activity_main_item, parent,        false       );


        return               new        ViewHolder(view);


 }





 @Override


        public               void        onBindViewHolder(ViewHolder holder,        int        position) {


 holder.setData(position);


 }





 @Override


        public               int        getItemCount() {


        return        20;


 }








        public               class        ViewHolder        extends        RecyclerView.ViewHolder        implements        View.OnClickListener {


 @BindView(R.id.textView)


 TextView textView;





        public        ViewHolder(View itemView) {


        super       (itemView);


 ButterKnife.bind(       this       , itemView);


 itemView.setOnClickListener(       this       );


 }





        public               void        setData(       int        position) {


 textView.setText("第" + position + "行");


 }





 @Override


        public               void        onClick(View view) {


        if        (mOnRvItemClick !=        null       )


 mOnRvItemClick.onItemClick(view, getAdapterPosition());


 }


 }





        /**


 * item点击接口


 */


        public               interface        onRecyclerViewItemClick {


        void        onItemClick(View v,        int        position);


 }





}


3.3 修改RecyclerView源码


这种方式一般不常见,也推荐使用。


四、RecycleView中的乱序处理


4.1问题由来


在RecycleView的使用过程中可能会出现这样,比如使用了checkbox控件,在勾选某项的checkbox之后,滑动checkbox的过程中后面的checkbox也被勾选上了,这种问题是由于RecycleView使用的复用的机制。


4.2解决办法


onBindViewHolder 绑定视图时重新更新checkbox的状态,如果在对Item的checkbox状态进行更新时,一定要对对应的数组或者map中对应的值进行更新,参见如下代码:


@Override


publicvoid        onBindViewHolder(ViewHolder holder, final        int               position       ) {


//设置checkBox改变监听


 holder.checkBox.setOnCheckedChangeListener(       new        CompoundButton.OnCheckedChangeListener() {





 @Override


publicvoid        onCheckedChanged(CompoundButton buttonView,        boolean        isChecked) {


//用map集合保存checkbox改变的状态值


        map       .       put       (       position       , isChecked);


 }


 });


// 用map集合保存checkbox不确定情况下的状态值


        if        (       map       .       get       (       position       ) == null) {


        map       .       put       (       position       , false);


 }


//用map中的值更新checkbox的状态


 holder.checkBox.setChecked(       map       .       get       (       position       ));


 }


4.3 乱序问题的进一步升级和处理


如果RecycleView列表中需要删除某项Item项时,在重复删除操作之后依旧可能出现乱序的情况(具体问题描述详情参考: ),该问题的处理步骤包括:


1.删除数组中对应的元素值


2.删除对应的Item项,并对整个Item列表进行调整。


五、参考博客链接如下


RecycleView的Item点击事件处理:




RecycleView的乱序处理: