首页 > 系统 > Android > 正文

学习Android Material Design(RecyclerView代替ListView)

2020-04-11 10:57:08
字体:
来源:转载
供稿:网友

本文实例实现一下 RecyclerView,代码比较简单,适合初学者,如有错误,欢迎指出。

复习 ListView

可以查看这篇文章深入浅出学习Android ListView基础,了解关于ListView 的基础知识。

实现过程中需要复写BaseAdapter,主要是这4个方法

  • public int getCount() :适配器中数据集中 数据的个数,即ListView需要显示的数据个数
  • public Object getItem(int position) : 获取数据集中与指定索引对应的数据项
  • public long getItemId(int position) : 获取指定行对应的ID
  • public View getView(int position, View convertView, ViewGroup parent) :获取每一个Item的显示内容

一般 ListView 每一项都是相同的布局,若想各个项实现不同的布局,可复写 getItemViewType和getViewTypeCount实现
RecyclerView 实现

1、xml 布局

下面是RecyclerView中每一项的布局 layout下面的item_article_type_1.xml

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:fresco="http://schemas.android.com/apk/res-auto" android:id="@+id/cv_item" android:layout_width="match_parent" android:layout_height="wrap_content" android:foreground="?android:attr/selectableItemBackground" app:cardCornerRadius="5dp" app:cardElevation="5dp" app:contentPadding="2dp"> <LinearLayout  android:layout_width="match_parent"  android:layout_height="wrap_content">  <com.facebook.drawee.view.SimpleDraweeView   android:id="@+id/rcv_article_photo"   android:layout_width="100dp"   android:layout_height="100dp"   android:layout_centerVertical="true"   fresco:actualImageScaleType="centerInside"   fresco:roundAsCircle="true"   fresco:roundingBorderColor="@color/lightslategray"   fresco:roundingBorderWidth="1dp" />  <LinearLayout   android:layout_width="0dp"   android:layout_height="match_parent"   android:layout_weight="1"   android:orientation="vertical">   <TextView    android:id="@+id/rcv_article_title"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="2dp"    android:gravity="center"    android:text="关于举办《经典音乐作品欣赏与人文审美》讲座的通知"    android:textColor="@color/primary_text" />   <!-- 新闻 发布时间 来源 阅读次数-->   <LinearLayout    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginTop="5dp"    android:gravity="center"    android:orientation="horizontal">    <TextView     android:id="@+id/rcv_article_date"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_marginLeft="10dp"     android:layout_marginRight="2dp"     android:text="2015-01-09" />    <TextView     android:id="@+id/rcv_article_source"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_marginLeft="2dp"     android:layout_marginRight="2dp"     android:text="科学研究院" />    <TextView     android:id="@+id/rcv_article_readtimes"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_marginLeft="2dp"     android:layout_marginRight="2dp"     android:text="1129次" />   </LinearLayout>   <TextView    android:id="@+id/rcv_article_preview"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="5dp"    android:ellipsize="end"    android:maxLines="2"    android:text="讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识..." />  </LinearLayout> </LinearLayout></android.support.v7.widget.CardView> 

布局思路就是 CardView里面嵌入了一个LinearLayout。图片部分用固定宽度100dp,文字部分利用android:layout_weight=”1”占据了其他部分。

TextView利用android:gravity=”center”使得标题的文字居中。

LinearLayout里面利用android:gravity=”center”使得“2015-01-09 科学研究院 1129次”居中,

新闻详情内容的TextView利用

android:maxLines="2"android:ellipsize="end"

将文章内容限定为2行,超出部分用省略号显示。

使用fresco这儿有个坑需要注意,请移步这篇文章

Android 之 Fresco 显示圆形图片 之坑

预览效果

新闻列表的 xml 文件,layout 文件夹下面的fragment_article.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" android:orientation="vertical"> <android.support.v7.widget.RecyclerView  android:id="@+id/rcv_article"  android:layout_width="match_parent"  android:layout_height="0dp"  android:layout_weight="1" /></LinearLayout>

2、Adapter 实现

主要步骤是:

根据上面的 item_article_type_1.xml实现一个 class ImageItemArticleViewHolder extends RecyclerView.ViewHolder
继承RecyclerView.Adapter ,class ItemArticleListAdapter extends RecyclerView.Adapter <...>
重写三个方法

  • public int getItemCount()
  • public TestAdapter.ImageItemArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
  • public void onBindViewHolder(ImageItemArticleViewHolder holder, int position)

public class ItemArticleAdapter extends RecyclerView.Adapter<ItemArticleAdapter.ImageItemArticleViewHolder> { //新闻列表 private List<ItemArticle> articleList; //context private Context context; private LayoutInflater mLayoutInflater; public ItemArticleAdapter(Context context,List<ItemArticle> articleList) {  this.context = context;  this.articleList = articleList;  mLayoutInflater = LayoutInflater.from(context); } @Override public ItemArticleAdapter.ImageItemArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  View view = mLayoutInflater.inflate(    R.layout.item_article_type_1, parent, false);  return new ImageItemArticleViewHolder(view); } @Override public void onBindViewHolder(ImageItemArticleViewHolder holder, int position) {  ItemArticle article = articleList.get(position);  holder.rcvArticlePhoto.setImageURI(Uri.parse(article.getImageUrl()));  holder.rcvArticleTitle.setText(article.getTitle());  holder.rcvArticleDate.setText(article.getPublishDate());  holder.rcvArticleSource.setText(article.getSource());  //注意这个阅读次数是 int 类型,需要转化为 String 类型  holder.rcvArticleReadtimes.setText(article.getReadTimes()+"次");  holder.rcvArticlePreview.setText(article.getPreview()); } @Override public int getItemCount() {  return articleList.size(); } class ImageItemArticleViewHolder extends RecyclerView.ViewHolder {  @InjectView(R.id.rcv_article_photo)  SimpleDraweeView rcvArticlePhoto;  @InjectView(R.id.rcv_article_title)  TextView rcvArticleTitle;  @InjectView(R.id.rcv_article_date)  TextView rcvArticleDate;  @InjectView(R.id.rcv_article_source)  TextView rcvArticleSource;  @InjectView(R.id.rcv_article_readtimes)  TextView rcvArticleReadtimes;  @InjectView(R.id.rcv_article_preview)  TextView rcvArticlePreview;  public ImageItemArticleViewHolder(View itemView) {   super(itemView);   ButterKnife.inject(this, itemView);  } }}

3、新闻实体类 javabean

有新闻的 index,图片 url,标题,发布时间,来源,阅读次数,新闻内容预览

/** * 新闻类,这是在 RecycleView 使用的新闻 javabean * 还有一个新闻详情javabean */public class ItemArticle { private int index; private String imageUrl; private String title; private String publishDate; private String source; private int readTimes; private String preview; public ItemArticle(int index, String imageUrl, String title, String publishDate, String source, int readTimes, String preview) {  this.index = index;  this.imageUrl = imageUrl;  this.title = title;  this.publishDate = publishDate;  this.source = source;  this.readTimes = readTimes;  this.preview = preview; } public int getIndex() {  return index; } public void setIndex(int index) {  this.index = index; } public String getImageUrl() {  return imageUrl; } public void setImageUrl(String imageUrl) {  this.imageUrl = imageUrl; } public String getTitle() {  return title; } public void setTitle(String title) {  this.title = title; } public String getPublishDate() {  return publishDate; } public void setPublishDate(String publishDate) {  this.publishDate = publishDate; } public String getSource() {  return source; } public void setSource(String source) {  this.source = source; } public int getReadTimes() {  return readTimes; } public void setReadTimes(int readTimes) {  this.readTimes = readTimes; } public String getPreview() {  return preview; } public void setPreview(String preview) {  this.preview = preview; }}

4、fragment 里面使用 RecyclerView

思路就是开启一个异步线程,读取多条新闻,加入List itemArticleList,由这个itemArticleList构造ItemArticleAdapter,最后利用setAdapter()方法给RecyclerView加上适配器。

public class ArticleFragment extends Fragment { private static final String STORE_PARAM = "param"; @InjectView(R.id.rcv_article) RecyclerView rcvArticle; private String mParam; //新闻列表数据 private List<ItemArticle> itemArticleList = new ArrayList<ItemArticle>(); //获取 fragment 依赖的 Activity,方便使用 Context private Activity mAct; public static Fragment newInstance(String param) {  ArticleFragment fragment = new ArticleFragment();  Bundle args = new Bundle();  args.putString(STORE_PARAM, param);  fragment.setArguments(args);  return fragment; } @Override public void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  if (getArguments() != null) {   mParam = getArguments().getString(STORE_PARAM);  } } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  View view = inflater.inflate(R.layout.fragment_article, null);  Log.i(STORE_PARAM, "in StoreFragment");  mAct = getActivity();  ButterKnife.inject(this, view);  return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {  super.onActivityCreated(savedInstanceState);  rcvArticle.setLayoutManager(new LinearLayoutManager(mAct));//这里用线性显示 类似于listview//  rcvArticle.setLayoutManager(new GridLayoutManager(mAct, 2));//这里用线性宫格显示 类似于grid view//  rcvArticle.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));//这里用线性宫格显示 类似于瀑布流  new LatestArticleTask().execute(); } @Override public void onDestroyView() {  super.onDestroyView();  ButterKnife.reset(this); } class LatestArticleTask extends AsyncTask<String, Void, List<ItemArticle>> {  @Override  protected void onPreExecute() {   super.onPreExecute();  }  @Override  protected List<ItemArticle> doInBackground(String... params) {   ItemArticle storeInfo1 =     new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "关于举办《经典音乐作品欣赏与人文审美》讲座的通知", "2015-01-09", "科学研究院", 1129,       "讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识...");   ItemArticle storeInfo2 =     new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "关于举办《经典音乐作品欣赏与人文审美》讲座的通知", "2015-01-09", "科学研究院", 1129,       "讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识...");   ItemArticle storeInfo3 =     new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "关于举办《经典音乐作品欣赏与人文审美》讲座的通知", "2015-01-09", "科学研究院", 1129,       "讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识...");   ItemArticle storeInfo4 =     new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "关于举办《经典音乐作品欣赏与人文审美》讲座的通知", "2015-01-09", "科学研究院", 1129,       "讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识...");   ItemArticle storeInfo5 =     new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "关于举办《经典音乐作品欣赏与人文审美》讲座的通知", "2015-01-09", "科学研究院", 1129,       "讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识...");   ItemArticle storeInfo6 =     new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "关于举办《经典音乐作品欣赏与人文审美》讲座的通知", "2015-01-09", "科学研究院", 1129,       "讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识...");   itemArticleList.add(storeInfo1);   itemArticleList.add(storeInfo2);   itemArticleList.add(storeInfo3);   itemArticleList.add(storeInfo4);   itemArticleList.add(storeInfo5);   itemArticleList.add(storeInfo6);   return itemArticleList;  }  @Override  protected void onPostExecute(List<ItemArticle> data) {   super.onPostExecute(data);   ItemArticleAdapter adapter = new ItemArticleAdapter(mAct, data);   rcvArticle.setAdapter(adapter);  } }}

效果图

利用修改布局,线性显示或者宫格显示。(以前宫格显示很麻烦,现在一条命令就好了,google 搞得这么简单,我们Android 工程师要失业的好伐?!!)

rcvArticle.setLayoutManager(new LinearLayoutManager(mAct));//这里用线性显示 类似于listview//  rcvArticle.setLayoutManager(new GridLayoutManager(mAct, 2));//这里用线性宫格显示 类似于grid view//  rcvArticle.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));//这里用线性宫格显示 类似于瀑布流

知识点

TextView需要有setText(int resid) 方法,但是这儿 int 表示 resourceId,如果我想把阅读次数(int 1123)赋给这个 TextView,不能使用这个方法。
需要把 int 转化为 String

int 转 String 有三种方法int i =8;String s =Integer.toString(i);String g =String.valueOf(i);String h =i+"";holder.rcvArticleReadtimes.setText(String.valueOf(article.getReadTimes())); 

总结 Todo List

  • Picasso 图片缓存库的学习
  • 实现 RecyclerView 每个项各自的布局

遇到的坑

rcvArticle.setLayoutManager()需要在onActivityCreated()方法里调用,如果在onCreateView()调用会抛出空指针异常。

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  View view = inflater.inflate(R.layout.fragment_one_latest, container, false);  mAct = getActivity();  //错误,需要在onActivityCreated里面调用  rcvArticle.setLayoutManager(new LinearLayoutManager(mAct));//这里用线性显示 类似于listview  ButterKnife.inject(this, view);  return view; }

java.lang.NullPointerException
at com.example.administrator.seenews.ui.fragment.common.ArticleFragment.onCreateView(ArticleFragment.java:111)

以上就是本文的全部内容,希望对大家的学习有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表