android (一)RecycleView组件的使用
先上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
更多相关文章
- Android里实现Bitmap图片的旋转和缩放
- Android开发点滴(13) -- Android数据库随同Android应用一同发布
- Android使用getIdentifier()获取资源Id的方法
- 你了解Android中的Activity吗?
- android中自定义checkbox的图片和大小
- Android(安卓)横竖屏切换小结
- Android(安卓)Material Design Library系列教程(一)
- android AlertDialog 捕获返回键
- [经验总结]eclipse转向android studio常见问题汇总