先上github为敬 https://github.com/linliangliang/RecycleView

RecyclerView是support:recyclerview-v7中提供的控件,新添加的一个用来取代ListView。RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件。RecyclerView和好处很多,例如缓存,预加载,相同item避免重复刷新。好处就不讲了。

这里挂一张图,但是觉得简单明了直接保存了,具体出自哪个找了好久还是没有找出来。如果有人遇到过可以通知一下我吧连接挂出来。

博客分三个部分,

第一个部分介绍使用RecyclerView实现三种布局形式,LinearLayoutManager (线性布局,分水平和垂直两种),GridLayoutManager (网格布局),StaggeredGridLayoutManager(流布局)。这里只是使用本地图片的显示

第二部分介绍使用RecyclerView+Glide+CardView实现动态加载网络图片,实现类似新闻app的新闻查看效果。并使用CardView美化效果。

第三部分介绍RecyclerView+Glide+CardView+SwipeRefreshLayout实现上下拉刷新列表。

第一个部分

一、RecyclerView实现三种布局

效果:(照片有点歪,能看就行哈哈哈,别问我问什么不用截图,第三种属于网络图片的加载直接贴上吧)

1、添加依赖

    compile 'com.android.support:cardview-v7:28.0.0'  // 这是cardView的依赖    implementation 'com.android.support:recyclerview-v7:28.0.0'    compile 'com.github.bumptech.glide:glide:3.5.2'

2、添加网络权限,因为我们待会要从网络上加载图片

    

3、编写布局

<?xml version="1.0" encoding="utf-8"?>                

4、有了android.support.v7.widget.RecyclerView组件后,我们还要定义item的样式,这里只有一张图片和一句话。recycleview_item.xml

<?xml version="1.0" encoding="utf-8"?>                        

item的样式最外面是一个CardView组件,会比我们自定义组件漂亮好多。CardView如何使用这么不再讲述。

5、有了android.support.v7.widget.RecyclerView组件和item后,我们在代码中为其添加内容。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private RecyclerView mRecyclerView;    private Button mButtonLinearLayout;    private Button mButtonLinearLayoutHorizatol;    private Button mButtonGrid;    private Button mButton;    private Button mLoadNetImage;    //item 显示所需    private String[] title = {"你的脸上云淡风轻,谁也不知道你的牙咬得有多紧",            "你走路带着风,谁也不知道你膝盖上仍有曾摔伤的淤青",            "你笑得没心没肺,没人知道你哭起来只能无声落泪。",            "要让人觉得毫不费力,只能背后极其努力。",            "我们没有改变不了的未来,只有不想改变的过去。",            " 过去已然存在,不是不想改变,是不能改变。",            "我们没有改变不了的未来,只有改变不了的过去。"    };    private int[] pic = {R.mipmap.ic_launcher, R.mipmap.ic_launcher,            R.mipmap.ic_launcher, R.mipmap.ic_launcher,            R.mipmap.ic_launcher, R.mipmap.ic_launcher,            R.mipmap.ic_launcher};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mRecyclerView = (RecyclerView) findViewById(R.id.rv_list);        mButtonLinearLayout = (Button) findViewById(R.id.btn_linearlayout);        mButtonLinearLayoutHorizatol = (Button) findViewById(R.id.btn_linearlayout_horizatol);        mButtonGrid = (Button) findViewById(R.id.btn_grid);        mButton = (Button) findViewById(R.id.btn);        mLoadNetImage = findViewById(R.id.btn_load_network_image);        mButtonLinearLayout.setOnClickListener(this);        mButtonGrid.setOnClickListener(this);        mButton.setOnClickListener(this);        mButtonLinearLayoutHorizatol.setOnClickListener(this);        mLoadNetImage.setOnClickListener(this);        // 创建一个线性布局管理器        LinearLayoutManager layoutManager = new LinearLayoutManager(this);        //设置垂直滚动,也可以设置横向滚动        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);        //RecyclerView设置布局管理器        mRecyclerView.setLayoutManager(layoutManager);        //RecyclerView设置Adapter        mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_linearlayout:                // 创建一个线性布局管理器                LinearLayoutManager layoutManager = new LinearLayoutManager(this);                //设置垂直滚动,也可以设置横向滚动                layoutManager.setOrientation(LinearLayoutManager.VERTICAL);                mRecyclerView.setLayoutManager(layoutManager);                mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));                break;            case R.id.btn_linearlayout_horizatol:                // 创建一个线性布局管理器                LinearLayoutManager layoutManager1 = new LinearLayoutManager(this);                //设置垂直滚动,也可以设置横向滚动                layoutManager1.setOrientation(LinearLayoutManager.HORIZONTAL);                mRecyclerView.setLayoutManager(layoutManager1);                mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));                break;            case R.id.btn_grid:                mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2)); //Grid视图                mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));                break;            case R.id.btn:                mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));                mRecyclerView.setAdapter(new RecyclerViewAdapter(this, title, pic));                break;            case R.id.btn_load_network_image:                Intent intent = new Intent();                intent.setClass(this, LoadNetworkIamgeActivity.class);                startActivity(intent);                break;        }    }}

代码很简单,然后我们需要为RecycleView添加一个适配器,并且这几种布局都是使用这一个适配器,是不是很强大,很牛p。

6,适配器RecyclerViewAdapter 

/** * Created by 林亮 on 2019/1/7 */public class RecyclerViewAdapter extends RecyclerView.Adapter {    private LayoutInflater mLayoutInflater;    private Context mContext;    private String[] mTitle;    private int[] mPic;    //通过构造方法将图片以及文字,上下文传递过去    public RecyclerViewAdapter(Context context, String[] title, int[] pic) {        mContext = context;        mTitle = title;        mPic = pic;        mLayoutInflater = LayoutInflater.from(context);    }    //我们创建一个ViewHolder并返回,ViewHolder必须有一个带有View的构造函数,这个View就是我们Item的根布局,在这里我们使用自定义Item的布局;    @Override    public NormalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        return new NormalViewHolder(mLayoutInflater.inflate(R.layout.recycleview_item, parent, false));    }    //将数据与界面进行绑定的操作    @Override    public void onBindViewHolder(NormalViewHolder holder, final int position) {        holder.mTextView.setText(mTitle[position]);        holder.mImageView.setBackgroundResource(mPic[position]);        holder.mCardView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mContext, mTitle[position], Toast.LENGTH_SHORT).show();            }        });    }    //获取数据的数量    @Override    public int getItemCount() {        return mTitle == null ? 0 : mTitle.length;    }    //自定义的ViewHolder,持有每个Item的的所有界面元素    public static class NormalViewHolder extends RecyclerView.ViewHolder {        TextView mTextView;        CardView mCardView;        ImageView mImageView;        public NormalViewHolder(View itemView) {            super(itemView);            mTextView = (TextView) itemView.findViewById(R.id.tv_text);            mCardView = (CardView) itemView.findViewById(R.id.cv_item);            mImageView = (ImageView) itemView.findViewById(R.id.iv_pic);        }    }}

其中NormalViewHolder 继承自RecyclerView.ViewHolder,比之前使用ListView简单多了。over。第一部分完成,如果使用过listView这里的代码就应该来说很简单了。但是我们在使用过程中基本都是从网络上加载图片。于是有了第二部分

第二部分、介绍使用RecyclerView+Glide加载网络图片

1、其实使用Glide加载网络图片的过程很简单之前加载本地图片的时候我们使用

holder.mImageView.setBackgroundResource(mPic[position]);

就是显示了本地图片,而使用网络图片也是一句话(在之前添加过依赖)

//用glide加载网络图片 并放入imageview中         Glide.with(mContext).load(mItemEntitys.get(position).getmImageUri()).into(holder.mImageview);

.with()的参数是上下文,.load()中的参数是图片的Uri,.into()的参数就是显示图片的ImageView了。

为了完整展示实现效果,这里还是将代码贴出来,因为有些细节还是不一样的。

2、编写item布局,item_water_fall.xml

<?xml version="1.0" encoding="utf-8"?>                                

3、加载网络图片的activity

import static com.zhengyuan.recyclerview.util.ImageUtil.imageUrls;/** * Created by 林亮 on 2019/1/7 */public class LoadNetworkIamgeActivity extends Activity {    private RecyclerView mRecyclerView;    SwipeRefreshLayout mSwipeRefreshLayout;    private List waterFallItemEntities;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        initView();        initData();//假装从服务器获取数据,不过这里的图片确实是网址        StaggeredGridLayout();//使用瀑布流布局    }    private void StaggeredGridLayout() {        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));        mRecyclerView.setAdapter(new WaterFallAdapter(this, waterFallItemEntities));        //mRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(this, 2));//添加分割线    }    private void initView() {        mRecyclerView = findViewById(R.id.recyclerView);        mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);//上下拉刷新加载列表        mSwipeRefreshLayout.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN);    }    private void initData() {        waterFallItemEntities = new ArrayList();        for (int i = 0; i < ImageUtil.imageUrls.length; i++) {            waterFallItemEntities.add(new WaterFallItemEntity("也许你现在仍然是一个人下班,一个人乘地铁,一个人上楼,一个人吃饭,一个人睡觉,一个人发呆。然而你却能一个人下班,一个人乘地铁,一个人上楼,一个人吃饭,一个人睡觉,一个人发呆。很多人离开另外一个人,就没有自己。而你却一个人,度过了所有。你的孤独,虽败犹荣。"                    , ImageUtil.imageUrls[i], "2019-1-" + (int) (Math.random() * 10)));        }    }}

其中的WaterFallItemEntity是定义的一个POJO对象,承载item对内容

4、WaterFallItemEntity:

//一个cardView 包含一个title,一个image,一个时间,一个内容(内容省略吧)和title一样public class WaterFallItemEntity {    private String mTitle;    private String mImageUri;    private String mTime;    public WaterFallItemEntity(String title, String imageUri, String time) {        mTitle = title;        mImageUri = imageUri;        mTime = time;    }    public String getmTitle() {        return mTitle;    }    public void setmTitle(String mTitle) {        this.mTitle = mTitle;    }    public String getmImageUri() {        return mImageUri;    }    public void setmImageUri(String mImageUri) {        this.mImageUri = mImageUri;    }    public String getmTime() {        return mTime;    }    public void setmTime(String mTime) {        this.mTime = mTime;    }}

5、最后就是适配器了

//瀑布流适配器public class WaterFallAdapter extends RecyclerView.Adapter {    private Context mContext;    private List mItemEntitys;    public WaterFallAdapter(Context content, List itemEntitys) {        this.mContext = content;        this.mItemEntitys = itemEntitys;    }    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        //获取item_layout的布局        View view = LayoutInflater.from(mContext).inflate(R.layout.item_water_fall, parent, false);        return new ViewHolder(view);    }    @Override    public void onBindViewHolder(ViewHolder holder, final int position) {        holder.mTitle.setText(mItemEntitys.get(position).getmTitle());        //用glide加载网络图片 并放入imageview中        Glide.with(mContext).load(mItemEntitys.get(position).getmImageUri()).into(holder.mImageview);        holder.mTime.setText(mItemEntitys.get(position).getmTime());        holder.mCardView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mContext, "点击了第" + position + "个卡片", Toast.LENGTH_SHORT).show();            }        });    }    //设置图片的点击事件    private void setItemListener(final ViewHolder holder, final int position, final String url) {        //如果holder为空 return;        if (holder == null) {            return;        }        //每个图片的点击事件        holder.mCardView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //显示大图功能以后再说                Toast.makeText(mContext, ">>>", Toast.LENGTH_SHORT).show();            }        });    }    @Override    public int getItemCount() {        return mItemEntitys.size();    }    public class ViewHolder extends RecyclerView.ViewHolder {        CardView mCardView;        TextView mTitle;        ImageView mImageview;        TextView mTime;        public ViewHolder(View view) {            super(view);            mCardView = (CardView) view.findViewById(R.id.cv_item);            mTitle = (TextView) view.findViewById(R.id.title);            mImageview = (ImageView) view.findViewById(R.id.image);            mTime = (TextView) view.findViewById(R.id.time);        }    }}

7、单位网络图片的来源还得给出

public class ImageUtil {    public final static String[] imageUrls = new String[]{            "https://img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg",            "https://img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg",            "https://img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg",            "https://img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg",            "https://img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg",            "https://img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg",            "https://img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg",            "https://img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg"    };}

8、关于recyclerview 分割线需要自己实现,可以实现不同的样式,具体怎么实现这么不讲述,大家可以参考

https://blog.csdn.net/yancychas/article/details/77484659

第三部分 介绍RecyclerView+Glide+CardView+SwipeRefreshLayout实现上下拉刷新列表。

使用RecycleView当然少不了需要刷新数据显示了。SwipRefreshLayout是Google推出的用来刷新的官方组件,不过它仅支持下拉刷新,不支持上拉刷新,不知道Google为什么不一起弄个组件就完了,不过既然SwipRefreshLayout不支持下拉刷新,那么我们就自己实现,就是点RecycleView下拉到底部,显示最后一个item的时候刷新数据。

1、我们在RecycleView的外面套一个SwipeRefreshLayout容器,可以看到这个组件来自android.support.v4.widget.SwipeRefreshLayout,需要添加v4的依赖。

                        

2、而activty还是在原来的LoadNetworkIamgeActivity 中写,先讲实现过程,最后附上完整的代码。

为了实现上拉刷新,我们这里使用LinearLayoutManager

        //StaggeredGridLayout();//使用瀑布流布局        LinearLayout();//在onCreata()中注释StaggeredGridLayout(),使用下面这个函数设置布局LinearLayoutManager layoutManager = null;private void LinearLayout() {        layoutManager = new LinearLayoutManager(LoadNetworkIamgeActivity.this);        //设置垂直滚动,也可以设置横向滚动        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);        mRecyclerView.setLayoutManager(layoutManager);        mAaterFallAdapter = new WaterFallAdapter(this, waterFallItemEntities);        mRecyclerView.setAdapter(mAaterFallAdapter);    }

3、在onCreata中添加上拉、下拉刷新的监听函数

         //初始化上拉刷新        initPullRefresh();        //初始化下拉刷新        initLoadMoreListener();

4、实现下拉刷新的函数

//mSwipeRefreshLayout的初始化//mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);//上下拉刷新加载列表//mSwipeRefreshLayout.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN);     /**     * 上拉刷新     */    private void initPullRefresh() {        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {            @Override            public void onRefresh() {                //新启动线程加载延时操作                new Thread(new Runnable() {                    @Override                    public void run() {                        //long beginTime = System.currentTimeMillis();//记录开始加载信息时间                        //模拟加载1秒                        try {                            sleep(1000);                        } catch (Exception e) {                            e.printStackTrace();                        }                        //更新数据源,随意添加两张图片                        for (int i = 2; i < 4; i++) {                            waterFallItemEntities.add(0, new WaterFallItemEntity("一个人吃饭,一个人睡觉,一个人发呆。然而你却能一个人下班,一个人乘地铁,一个人上楼,一个人吃饭,一个人睡觉,一个人发呆。很多人离开另外一个人,就没有自己。而你却一个人,度过了所有。你的孤独,虽败犹荣。"                                    , ImageUtil.imageUrls[i], "2019-1-" + (int) (Math.random() * 10)));                        }                        //下面的handle在加载信息完成后调用                        Message message = new Message();                        message.what = 200;                        myHandle.sendMessage(message);                    }                }).start();            }        });    }

为mSwipeRefreshLayout设置监听事件,在onRefresh中刷新数据,在onRefresh新启动一个线程,并添加一个延时操作模拟从网络上获取数据,刷新数据就行新添加两张图片。

5、最后在自定义的handle中刷新数据,停止刷新操作

MyHandle myHandle = new MyHandle(LoadNetworkIamgeActivity.this);    private List waterFallItemEntities = new ArrayList();    /**     * 刷新后更新数据源     */    public static class MyHandle extends Handler {        WeakReference weakReference = null;        public MyHandle(LoadNetworkIamgeActivity context) {            super();            weakReference = new WeakReference(context);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (weakReference != null && msg != null) {                LoadNetworkIamgeActivity activity = weakReference.get();                if (msg.what == 200) {                    //刷新结束,隐藏刷新动画                    activity.mSwipeRefreshLayout.setRefreshing(false);                    activity.mAaterFallAdapter.notifyDataSetChanged();                    Toast.makeText(activity, "加载成功", Toast.LENGTH_SHORT).show();                }            }        }    }

 

6、最后实现上拉刷新数据的函数

/**     * 通过监听RecycleView下拉到底部,实现下拉刷新     */    private void initLoadMoreListener() {        Log.i("test==", "onRefresh");        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            int lastVisibleItem;            @Override            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                lastVisibleItem = layoutManager.findLastVisibleItemPosition();//                //判断RecyclerView的状态 是空闲时,同时,是最后一个可见的ITEM时才加载                if (/*newState == RecyclerView.SCROLL_STATE_IDLE &&*/ lastVisibleItem + 3 == mAaterFallAdapter.getItemCount()) {                    new Handler().postDelayed(new Runnable() {                        @Override                        public void run() {                            List footerDatas = new ArrayList();                            for (int i = 0; i < 2; i++) {                                WaterFallItemEntity waterFallItemEntity = new WaterFallItemEntity("一个人的生活"                                        , ImageUtil.imageUrls[i], "2019-1-" + (int) (Math.random() * 10));                                footerDatas.add(waterFallItemEntity);                            }                            mAaterFallAdapter.AddFooterItem(footerDatas);                            Toast.makeText(LoadNetworkIamgeActivity.this, "更新了 " + footerDatas.size() + " 条目数据", Toast.LENGTH_SHORT).show();                        }                    }, 1);                }            }            @Override            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);            }        });    }

这里是对mRecyclerView添加一个滑动监听事件,lastVisibleItem 表示最后一个item显示的position。如果 if (lastVisibleItem + 3 == mAaterFallAdapter.getItemCount()) 倒数第三个显示出来,就再加载两个图片。这样就可以避免到最后一个让用户去等待加载图片,用户体验更好。

上拉下拉刷新数据的操作就完成。

整体代码由于博客篇幅较长这里就不在贴了,需要的可以在git上下载下来查看LoadNetworkIamgeActivity.java

 

(二)RecycleView组件进阶,实现加载不同类型的子项 

https://blog.csdn.net/qq_25066049/article/details/86495178

更多相关文章

  1. Android里实现Bitmap图片的旋转和缩放
  2. Android开发点滴(13) -- Android数据库随同Android应用一同发布
  3. Android使用getIdentifier()获取资源Id的方法
  4. 你了解Android中的Activity吗?
  5. android中自定义checkbox的图片和大小
  6. Android(安卓)横竖屏切换小结
  7. Android(安卓)Material Design Library系列教程(一)
  8. android AlertDialog 捕获返回键
  9. [经验总结]eclipse转向android studio常见问题汇总

随机推荐

  1. TextView跑马灯效果
  2. Android版本的RSA非对称加密实现
  3. 目录
  4. ListPreference之entries和entryValues
  5. Android技术之ListView分割线显示和隐藏
  6. Android使用第三方或者自制字体库(Typesp
  7. Android掌上背包游(1)
  8. Android开发之InstanceState详解
  9. android 获取sim卡运营商信息
  10. Android启动画面实现