当前位置: 移动技术网 > IT编程>移动开发>Android > Android项目实战之仿网易新闻的页面(RecyclerView )

Android项目实战之仿网易新闻的页面(RecyclerView )

2019年07月24日  | 移动技术网IT编程  | 我要评论

走出奔妹房间,吴玥菲,李悦是谁的儿子

本文实例实现一个仿网易新闻的页面,上面是轮播的图片,下面是 recyclerview 显示新闻列表,具体内容如下

错误方法

<?xml version="1.0" encoding="utf-8"?>
<linearlayout ...>
 <viewpager ... />

 <android.support.v7.widget.recyclerview .../>

</linearlayout>

这样布局 viewpager 在 recyclerview 的上面,如果不做特殊处理,当下滑 recyclerview 加载更多内容的时候,viewpager会固定不动。

正确的效果是下滑加载更多的时候,viewpager 会滑出页面,释放空间供其他内容展示。
一、解决思路

方法有两种

  • viewpager作为 recyclerview 的第0项,也就是 header(本文采用该方法)
  • 利用scrollview,重写一些方法解决滑动冲突

总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_latest"
  android:layout_width="match_parent"
  android:layout_height="0dp"
  android:layout_weight="1" />

</linearlayout>

很简单,一个recyclerview就行了

头部 viewpager 的viewholder_article_header.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">

 <!--viewpager 热门文章图片展示-->
 <framelayout
  android:layout_width="match_parent"
  android:layout_height="200dp"
  android:background="@color/gray_light">

  <android.support.v4.view.viewpager
   android:id="@+id/vp_hottest"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@color/colorprimary" />

  <linearlayout
   android:id="@+id/ll_hottest_indicator"
   android:layout_width="wrap_content"
   android:layout_height="20dp"
   android:layout_gravity="bottom|right"
   android:layout_marginbottom="5dp"
   android:layout_marginright="10dp"
   android:layout_margintop="5dp"
   android:gravity="center"
   android:orientation="horizontal" />
 </framelayout>
</linearlayout>

framelayout里面的viewpager和linearlayout是覆盖显示的,实现在图片的下方有个小圆点标记滑动到了第一张图片。

新闻项 viewholder_article_item.xml 布局

<android.support.v7.widget.cardview
 xmlns:android="http://schemas.android.com/apk/res/android"
 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"
 app:cardcornerradius="5dp"
 app:cardelevation="5dp"
 app:contentpadding="2dp">


 <linearlayout
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal">

  <com.facebook.drawee.view.simpledraweeview
   android:id="@+id/rcv_article_photo"
   android:layout_width="100dp"
   android:layout_height="100dp"
   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="0dp"
    android:layout_weight="1"
    android:layout_marginleft="10dp"
    android:layout_margintop="5dp"
    android:ellipsize="end"
    android:maxlines="2"
    android:text="讲座主要内容:以中、西方音乐历史中经典音乐作品为基础,通过作曲家及作品创作背景、相关音乐文化史知识及音乐欣赏常识..." />

  </linearlayout>
 </linearlayout>

</android.support.v7.widget.cardview>

这篇文章 android material design学习之recyclerview代替 listview 实现了不加 viewpager,利用 recyclerview 展示新闻列表的功能。

recyclerview 的适配器

/**
 * 新闻列表的适配器
 * 01-14 头部是 viewpager,下面是列表新闻
 * created by tomchen on 1/11/16.
 */
public class articleadapter extends recyclerview.adapter<recyclerview.viewholder> {

 private static final int type_header = 0;
 private static final int type_item = 1;

 //头部固定为 张图片
 private static final int num_image = 4;

 //handler 用到的参数值
 private static final int uptate_viewpager = 0;

 //新闻列表
 private list<itemarticle> articlelist;

 //设置当前 第几个图片 被选中
 private int currentindex = 0;

 //context
 private context context;

 private layoutinflater mlayoutinflater;

 private imageview[] mcircleimages;//底部只是当前页面的小圆点


 public articleadapter(context context, list<itemarticle> articlelist) {
  this.context = context;

  //头部viewpager图片固定是7张,剩下的是列表的数据
  this.articlelist = articlelist;
  mlayoutinflater = layoutinflater.from(context);
 }

 @override
 public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) {
  //理论上应该把最可能返回的 type 放在前面
  view view = null;

  if (viewtype == type_item) {
   view = mlayoutinflater.inflate(
     r.layout.viewholder_article_item, parent, false);
   return new itemarticleviewholder(view);
  }
  //头部返回 viewpager 实现的轮播图片
  if (viewtype == type_header) {
   view = mlayoutinflater.inflate(
     r.layout.viewholder_article_header, parent, false);
   return new headerarticleviewholder(view);
  }

  return null;
//  //可以抛出异常,没有对应的view类型
//  throw new runtimeexception("there is no type that matches the type " + viewtype + " + make sure your using types correctly");

 }

 @override
 public void onbindviewholder(recyclerview.viewholder holder, int position) {
  if (holder instanceof itemarticleviewholder) {
   //转型
   itemarticleviewholder newholder = (itemarticleviewholder) holder;
   //注意recyclerview第0项是 viewpager 占据了0 1 2 3图片
   //那么下面的列表展示是 recyclerview 的第1项,从第4项开始
   itemarticle article = articlelist.get(position + num_image - 1);
   newholder.rcvarticlephoto.setimageuri(uri.parse(article.getimageurl()));
   newholder.rcvarticletitle.settext(article.gettitle());
   newholder.rcvarticledate.settext(article.getpublishdate());
   newholder.rcvarticlesource.settext(article.getsource());
   //注意这个阅读次数是 int 类型,需要转化为 string 类型
   newholder.rcvarticlereadtimes.settext(article.getreadtimes() + "次");
   newholder.rcvarticlepreview.settext(article.getpreview());
  } else if (holder instanceof headerarticleviewholder) {
   headerarticleviewholder newholder = (headerarticleviewholder) holder;

   list<itemarticle> headers = articlelist.sublist(0, num_image );
   headerimageadapter imageadapter = new headerimageadapter(context, headers);

   setupviewpager(newholder.vphottest, newholder.llhottestindicator, headers);

  }
 }


 private void setupviewpager(final viewpager vp, linearlayout llbottom, final list<itemarticle> headerarticles) {
  headerimageadapter imageadapter = new headerimageadapter(context, headerarticles);
  //??这儿有些疑惑,adapter 里面嵌套设置 adapter 是否优雅?
  vp.setadapter(imageadapter);

  final handler mhandler = new handler() {
   public void handlemessage(message msg) {
    switch (msg.what) {
     case uptate_viewpager:
      if (msg.arg1 != 0) {
       vp.setcurrentitem(msg.arg1);
      } else {
       //false 当从末页调到首页是,不显示翻页动画效果,
       vp.setcurrentitem(msg.arg1, false);
      }
      break;
    }
   }
  };

  //下面是设置动画切换的样式
  vp.setpagetransformer(true, new rotateuptransformer());

  //创建底部指示位置的导航栏
  final imageview[] mcircleimages = new imageview[headerarticles.size()];

  for (int i = 0; i < mcircleimages.length; i++) {
   imageview imageview = new imageview(context);
   linearlayout.layoutparams params = new linearlayout.layoutparams(10, 10);
   params.setmargins(5, 0, 5, 0);
   imageview.setlayoutparams(params);
   if (i == 0) {
    imageview.setbackgroundresource(r.drawable.indicator_select);
   } else {
    imageview.setbackgroundresource(r.drawable.indicator_not_select);
   }

   mcircleimages[i] = imageview;
   //把指示作用的原点图片加入底部的视图中
   llbottom.addview(mcircleimages[i]);

  }

  vp.addonpagechangelistener(new viewpager.onpagechangelistener() {
   //图片左右滑动时候,将当前页的圆点图片设为选中状态
   @override
   public void onpageselected(int position) {
    // 一定几个图片,几个圆点,但注意是从0开始的
    int total = mcircleimages.length;
    for (int j = 0; j < total; j++) {
     if (j == position) {
      mcircleimages[j].setbackgroundresource(r.drawable.indicator_select);
     } else {
      mcircleimages[j].setbackgroundresource(r.drawable.indicator_not_select);
     }
    }

    //设置全局变量,currentindex为选中图标的 index
    currentindex = position;
   }

   @override
   public void onpagescrolled(int i, float v, int i1) {

   }

   @override
   public void onpagescrollstatechanged(int state) {

    //实现切换到末尾后返回到第一张
    switch (state) {
     // 手势滑动
     case viewpager.scroll_state_dragging:
      break;

     // 界面切换中
     case viewpager.scroll_state_settling:
      break;

     case viewpager.scroll_state_idle:// 滑动结束,即切换完毕或者加载完毕
      // 当前为最后一张,此时从右向左滑,则切换到第一张
      if (vp.getcurrentitem() == vp.getadapter()
        .getcount() - 1) {
       vp.setcurrentitem(0, false);
      }
      // 当前为第一张,此时从左向右滑,则切换到最后一张
      else if (vp.getcurrentitem() == 0) {
       vp.setcurrentitem(vp.getadapter()
         .getcount() - 1, false);
      }
      break;

     default:
      break;
    }
   }
  });


  //设置自动轮播图片,5s后执行,周期是5s

  timer timer = new timer();
  timer.schedule(new timertask() {
   @override
   public void run() {
    message message = new message();
    message.what = uptate_viewpager;
    if (currentindex == headerarticles.size() - 1) {
     currentindex = -1;
    }
    message.arg1 = currentindex + 1;
    mhandler.sendmessage(message);
   }
  }, 6000, 6000);
 }

 @override
 public int getitemcount() {
  //因为多了一个头部,所以是+1,但是头部 viewpager 占了7个
  //所以实际是少了6个
  return articlelist.size() + 1 - num_image;
 }

 @override
 public int getitemviewtype(int position) {
  if (position == 0)
   return type_header;
  else
   return type_item;
 }


 class headerarticleviewholder extends recyclerview.viewholder {

  //轮播的最热新闻图片
  @injectview(r.id.vp_hottest)
  viewpager vphottest;
  //轮播图片下面的小圆点
  @injectview(r.id.ll_hottest_indicator)
  linearlayout llhottestindicator;

  //学院广播信息
  @injectview(r.id.tv_college_broadcast)
  textview tvcollegebroadcast;

  public headerarticleviewholder(view itemview) {
   super(itemview);
   butterknife.inject(this, itemview);
  }
 }

 class itemarticleviewholder 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 itemarticleviewholder(view itemview) {
   super(itemview);
   butterknife.inject(this, itemview);
  }
 }


}

itemarticleviewholder是列表展示的新闻项的 viewholder,对应了上面的 viewholder_article_item.xml。

headerarticleviewholder 是头部 viewpager 的 viewholder, 对应viewholder_article_header.xml

note

  • 本文上面的 viewpager 轮播4幅图片,所以getitemcount()需要复写
  • list headers = articlelist.sublist(0, num_image );得到头部图片的数据
  • itemarticle article = articlelist.get(position + num_image - 1);得到下面新闻项的数据
  • getitemviewtype(int position)根据position判断是不是头部viewpager
  • oncreateviewholder(viewgroup parent, int viewtype)根据viewtype生成头部图片或者下面新闻项的viewholder

二、疑惑及后续计划

除了将 viewpager 作为 recyclerview 第一项,还有一张方法就是利用scrollview,大家可以进行研究。

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网