android (一)RecycleView组件的使用

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

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

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

android (一)RecycleView组件的使用_第1张图片

博客分三个部分,

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

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

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

第一个部分

一、RecyclerView实现三种布局

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

android (一)RecycleView组件的使用_第2张图片android (一)RecycleView组件的使用_第3张图片android (一)RecycleView组件的使用_第4张图片

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、编写布局




    

    

        

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




    

        

        
    

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




    

        

        

        
    

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

你可能感兴趣的:(android)