首页 > 系统 > Android > 正文

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

2019-10-24 20:26:53
字体:
来源:转载
供稿:网友
这篇文章主要介绍了Android项目实战之仿网易新闻的页面,ViewPager作为RecyclerView的Header
 

本文实例实现一个仿网易新闻的页面,上面是轮播的图片,下面是 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 sscc实现了不加 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,大家可以进行研究。

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



注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表