【android】RecyclerView的使用

来源:互联网 发布:电动伸缩大门的数据 编辑:程序博客网 时间:2024/05/22 16:14

看这里
这里写图片描述

RecyclerView

用于在有限的窗口展示大量的数据集。可以通过设置它提供的不同 LayoutManager (控制显示的方式)、ItemDecoration (控制 Item 间的间隔,可绘制)、ItemAnimator (控制 Item 增删的动画)实现一些效果。

可以看出,相比 ListView ,RecyclerView在功能上没有什么大的不同,不同之处在于实现了高度的解耦,给予开发人员充分的自由,所以可以用这个控件实现 ListView、 GirdView,瀑布流等效果。

基础功能使用:

mRecyclerView = findView(R.id.id_recyclerview);//设置布局管理器mRecyclerView.setLayoutManager(layout);//设置adaptermRecyclerView.setAdapter(adapter)//设置Item增加、移除动画mRecyclerView.setItemAnimator(new DefaultItemAnimator());//添加分割线mRecyclerView.addItemDecoration(new DividerItemDecoration(                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

一个小例子

1、在 build.gradle 中导入包

compile 'com.android.support:recyclerview-v7:24.+'

2、写布局文件

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.chandelier.recyclerview.MainActivity">        <android.support.v7.widget.RecyclerView            android:id = "@+id/recyclerViewId"            android:layout_width="match_parent"            android:layout_height="match_parent" /></RelativeLayout>

item.xml:

<?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">    <ImageView        android:id="@+id/pic_id"        android:scaleType="centerCrop"        android:layout_marginTop="5dp"        android:layout_marginEnd="5dp"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

3、实现:

MainActivity.java:

package com.chandelier.recyclerview;import android.os.AsyncTask;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.text.TextUtils;import android.util.Log;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    private static String TAG ="MainActivity";    private RecyclerView recyclerView;    private myAdapter mAdapter;    private int lastVisibleItem ;    private LinearLayoutManager linearLayoutManager;    private okhttpClass okhttp;    private int page = 1;    private List<picRes>  more;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        try {            okhttp = new okhttpClass();        } catch (IOException e) {            e.printStackTrace();        }        more= new ArrayList<>();//用来存放要加载的 Item(在这里是图片)对象(主要是url)        initView();//初始化布局        setListener();//设置监听事件        new GetData().execute("http://gank.io/api/data/福利/10/1");//先加载一些 Item    }    private void initView(){        recyclerView = (RecyclerView)findViewById(R.id.recyclerViewId);        linearLayoutManager = new LinearLayoutManager(this);        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);        recyclerView.setLayoutManager(linearLayoutManager);    }    private void setListener(){        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                if (newState == RecyclerView.SCROLL_STATE_IDLE                        && lastVisibleItem +2>=linearLayoutManager.getItemCount()) {                    new GetData().execute("http://gank.io/api/data/福利/10/"+(++page));                }            }            @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();            }        });    }    private class GetData extends AsyncTask<String, Integer, String> {        @Override        protected String doInBackground(String... params) {            String responce = null;            try {                responce = okhttp.getOp(params[0]);            } catch (IOException e) {                e.printStackTrace();            }            return responce;        }        protected void onPostExecute(String result) {            super.onPostExecute(result);            if(!TextUtils.isEmpty(result)){                JSONObject jsonObject;                JSONArray jsonarray = new JSONArray();                int count = 0;                try {                    jsonObject = new JSONObject(result);                    jsonarray = jsonObject.getJSONArray("results");                    count = jsonarray.length();                } catch (JSONException e) {                    e.printStackTrace();                }                String[] shujus = new String[count];                for (int x = 0; x < count; x++){                    try {                        shujus[x] = jsonarray.getJSONObject(x).getString("url");                        Log.i(TAG,"shujus["+x+"]:"+shujus[x]);                        picRes pic = new picRes(shujus[x]);                        more.add(pic);                        Log.i(TAG,"将pic加入到more中:"+x);                    } catch (JSONException e) {                        e.printStackTrace();                    }                }                if(mAdapter==null){                    mAdapter = new myAdapter(MainActivity.this,more);                    Log.i(TAG,"new 一个 myAdapter。");                    recyclerView.setAdapter(mAdapter);                    Log.i(TAG,"设置好 一个 myAdapter。");                }else{                    mAdapter.notifyDataSetChanged();                }            }        }    }}

GetData:继承自 AyncTask,主要重写了两个方法。

  • doInBackground(String... params):这个里面的代码在子线程中执行,执行一些耗时操作,这里主要使用 okHttp 进行网络请求,这里我对 okhttp 进行了小小的封装,下面会写到。
  • onPostExecute(String result):这个方法是当后台任务执行完毕并通过 return 返回时调用。在这个方法里我主要是对网络请求返回的数据进行解析,将图片的url 存储到 picRes 中,picRes 会在下面贴,就是用来存储 Item 信息的一个类。并且构造一个适配器,并为 recyclerView 设置该适配器。

setListener():这个方法里主要是做当用户滑动屏幕时,剩下的 item 少于两个时,自动加载下一页的工作。注意:添加了监听器不要忘记清除。

  • onScrolled (RecyclerView recyclerView,int dx,int dy):当滚动完成的时候,会调用此方法,第一个参数,表示哪一个 RecyclerView 会被调用;第二个参数表示水平滚动量;第三个参数垂直滚动量。
  • onScrollStateChanged (RecyclerView recyclerView,int newState):RecyclerView 的滚动状态发生改变的时候,该方法会被回调。第二个参数表示更新的滚动状态,有三种:
    • SCROLL_STATE_IDLE:RecyclerView 目前不滚动。
    • SCROLL_STATE_DRAGGING:RecyclerView 当前正在被外部输入拖动,例如用户触摸输入。
    • SCROLL_STATE_SETTLING:RecyclerView 目前正在移动到最终位置,而不再外部控制下。

这里面的 okhttpclass :

package com.chandelier.recyclerview;import android.util.Log;import com.squareup.okhttp.OkHttpClient;import com.squareup.okhttp.Request;import com.squareup.okhttp.Response;import com.squareup.okhttp.ResponseBody;import java.io.IOException;public class okhttpClass {    OkHttpClient mOkHttpClient;    String TAG = "okhttpClass";    public okhttpClass() throws IOException {        Log.i(TAG,"in okhttpClass!");        mOkHttpClient = new OkHttpClient();    }    public String getOp(String url) throws IOException{        Log.i(TAG,"in getOp!");        Request request = new Request.Builder().url(url).build();        Response response = mOkHttpClient.newCall(request).execute();        Log.i(TAG,"get responce");        String str;        if (response.isSuccessful()){            ResponseBody responceBody = response.body();            str = responceBody.string();        }else{            return "error";        }        return str;    }}

picRes :

package com.chandelier.recyclerview;public class picRes{    private String url;//图片地址    public picRes(String url){        this.url = url;    }    public String getUrl() {        return url;    }}

myAdapter:

package com.chandelier.recyclerview;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import com.squareup.picasso.Picasso;import java.util.List;public class myAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {    private List<picRes> data;    private LayoutInflater inflater;    private Context context;    public myAdapter(Context context,List<picRes> data) {        this.context = context;        this.data = data;        inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);    }    public class myViewHolder extends RecyclerView.ViewHolder{        public ImageView iv;        public myViewHolder(View itemView) {            super(itemView);            iv= (ImageView) itemView.findViewById(R.id.pic_id);        }    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View itemView = inflater.inflate(R.layout.item, parent, false);        return new myViewHolder(itemView);    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        Picasso.with(context).load(data.get(position).getUrl()).into(((myViewHolder)holder).iv);    }    @Override    public int getItemCount() {        return data!=null?data.size():0;    }}

先看看重写的方法吧

  • int getItemCount():返回适配器中数据集中的 Item 的总数。
  • void onBindViewHolder(RecyclerView.ViewHolder holder, int position):由 RecyclerView 调用来在指定的位置显示数据,这个方法应该在定的位置更新 itemView 的内容。
    • 请注意,与ListView不同,如果 item 的位置在数据集中更改,则 RecyclerView 将不会再次调用这个方法,除非 item 本身无效或者新的位置无法确定。因此,我们应该只在获取此方法中的相关数据 item 时使用 position 这个参数,并且不应该保留这个参数的副本。如果我们在之后需要一个 item 的 position (比如在监听器中),应该使用 getAdapaterPosition() 方法。如果适配器可以处理有效的数据,就重写此方法。
    • 所以在这个方法中,我做的操作是将图片加载到 ViewHolder 中。这里使用到了 Picasso,picasso 是 Square 公司开源的一个 android图形缓存库,可以实现图片下载和缓存的功能,就像这个方法中,仅仅用一行代码就能实现图片的异步加载。他还解决了 android 中加载图片时需要解决的一些常见问题。后面我可能会写一篇博客详细说明,吧。
  • RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType):当 RecyclerView 一个新的 ViewHolder 代表一个指定类型的 Item 时调用。一个新的 ViewHolder 应该以一个新的View,即可以代表给定类型的 item来构建。我们可以手动创建一个新的 View, 也可以从 xml 布局文件中 inflate 他,这里我使用的就是 inflate 。创建的 ViewHolder 将用于 onBindViewHolder() 中显示适配器的 item。由于它将重新用于在数据集中显示不同的项目,所以缓存对视图子视图的引用是以一个好主意,以避免不必要的 findViewById(int) 调用。

源码地址:https://github.com/Chandelierr/recyclerview

0 0