Android项目实战之仿网易新闻的页面(RecyclerView )
本文实例实现一个仿网易新闻的页面,上面是轮播的图片,下面是RecyclerView显示新闻列表,具体内容如下
错误方法
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayout...> <ViewPager.../> <android.support.v7.widget.RecyclerView.../> </LinearLayout>
这样布局ViewPager在RecyclerView的上面,如果不做特殊处理,当下滑RecyclerView加载更多内容的时候,ViewPager会固定不动。
正确的效果是下滑加载更多的时候,ViewPager会滑出页面,释放空间供其他内容展示。
一、解决思路
方法有两种
- ViewPager作为RecyclerView的第0项,也就是Header(本文采用该方法)
- 利用ScrollView,重写一些方法解决滑动冲突
总xml布局
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns: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布局
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns: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>
这篇文章AndroidMaterialDesign学习之RecyclerView代替ListViewsscc实现了不加ViewPager,利用RecyclerView展示新闻列表的功能。
RecyclerView的适配器
/**
*新闻列表的适配器
*01-14头部是ViewPager,下面是列表新闻
*Createdbytomchenon1/11/16.
*/
publicclassArticleAdapterextendsRecyclerView.Adapter<RecyclerView.ViewHolder>{
privatestaticfinalintTYPE_HEADER=0;
privatestaticfinalintTYPE_ITEM=1;
//头部固定为张图片
privatestaticfinalintNUM_IMAGE=4;
//Handler用到的参数值
privatestaticfinalintUPTATE_VIEWPAGER=0;
//新闻列表
privateList<ItemArticle>articleList;
//设置当前第几个图片被选中
privateintcurrentIndex=0;
//context
privateContextcontext;
privateLayoutInflatermLayoutInflater;
privateImageView[]mCircleImages;//底部只是当前页面的小圆点
publicArticleAdapter(Contextcontext,List<ItemArticle>articleList){
this.context=context;
//头部viewpager图片固定是7张,剩下的是列表的数据
this.articleList=articleList;
mLayoutInflater=LayoutInflater.from(context);
}
@Override
publicRecyclerView.ViewHolderonCreateViewHolder(ViewGroupparent,intviewType){
//理论上应该把最可能返回的TYPE放在前面
Viewview=null;
if(viewType==TYPE_ITEM){
view=mLayoutInflater.inflate(
R.layout.viewholder_article_item,parent,false);
returnnewItemArticleViewHolder(view);
}
//头部返回ViewPager实现的轮播图片
if(viewType==TYPE_HEADER){
view=mLayoutInflater.inflate(
R.layout.viewholder_article_header,parent,false);
returnnewHeaderArticleViewHolder(view);
}
returnnull;
////可以抛出异常,没有对应的View类型
//thrownewRuntimeException("thereisnotypethatmatchesthetype"+viewType+"+makesureyourusingtypescorrectly");
}
@Override
publicvoidonBindViewHolder(RecyclerView.ViewHolderholder,intposition){
if(holderinstanceofItemArticleViewHolder){
//转型
ItemArticleViewHoldernewHolder=(ItemArticleViewHolder)holder;
//注意RecyclerView第0项是ViewPager占据了0123图片
//那么下面的列表展示是RecyclerView的第1项,从第4项开始
ItemArticlearticle=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());
}elseif(holderinstanceofHeaderArticleViewHolder){
HeaderArticleViewHoldernewHolder=(HeaderArticleViewHolder)holder;
List<ItemArticle>headers=articleList.subList(0,NUM_IMAGE);
HeaderImageAdapterimageAdapter=newHeaderImageAdapter(context,headers);
setUpViewPager(newHolder.vpHottest,newHolder.llHottestIndicator,headers);
}
}
privatevoidsetUpViewPager(finalViewPagervp,LinearLayoutllBottom,finalList<ItemArticle>headerArticles){
HeaderImageAdapterimageAdapter=newHeaderImageAdapter(context,headerArticles);
//??这儿有些疑惑,Adapter里面嵌套设置Adapter是否优雅?
vp.setAdapter(imageAdapter);
finalHandlermHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
switch(msg.what){
caseUPTATE_VIEWPAGER:
if(msg.arg1!=0){
vp.setCurrentItem(msg.arg1);
}else{
//false当从末页调到首页是,不显示翻页动画效果,
vp.setCurrentItem(msg.arg1,false);
}
break;
}
}
};
//下面是设置动画切换的样式
vp.setPageTransformer(true,newRotateUpTransformer());
//创建底部指示位置的导航栏
finalImageView[]mCircleImages=newImageView[headerArticles.size()];
for(inti=0;i<mCircleImages.length;i++){
ImageViewimageView=newImageView(context);
LinearLayout.LayoutParamsparams=newLinearLayout.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(newViewPager.OnPageChangeListener(){
//图片左右滑动时候,将当前页的圆点图片设为选中状态
@Override
publicvoidonPageSelected(intposition){
//一定几个图片,几个圆点,但注意是从0开始的
inttotal=mCircleImages.length;
for(intj=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
publicvoidonPageScrolled(inti,floatv,inti1){
}
@Override
publicvoidonPageScrollStateChanged(intstate){
//实现切换到末尾后返回到第一张
switch(state){
//手势滑动
caseViewPager.SCROLL_STATE_DRAGGING:
break;
//界面切换中
caseViewPager.SCROLL_STATE_SETTLING:
break;
caseViewPager.SCROLL_STATE_IDLE://滑动结束,即切换完毕或者加载完毕
//当前为最后一张,此时从右向左滑,则切换到第一张
if(vp.getCurrentItem()==vp.getAdapter()
.getCount()-1){
vp.setCurrentItem(0,false);
}
//当前为第一张,此时从左向右滑,则切换到最后一张
elseif(vp.getCurrentItem()==0){
vp.setCurrentItem(vp.getAdapter()
.getCount()-1,false);
}
break;
default:
break;
}
}
});
//设置自动轮播图片,5s后执行,周期是5s
Timertimer=newTimer();
timer.schedule(newTimerTask(){
@Override
publicvoidrun(){
Messagemessage=newMessage();
message.what=UPTATE_VIEWPAGER;
if(currentIndex==headerArticles.size()-1){
currentIndex=-1;
}
message.arg1=currentIndex+1;
mHandler.sendMessage(message);
}
},6000,6000);
}
@Override
publicintgetItemCount(){
//因为多了一个头部,所以是+1,但是头部ViewPager占了7个
//所以实际是少了6个
returnarticleList.size()+1-NUM_IMAGE;
}
@Override
publicintgetItemViewType(intposition){
if(position==0)
returnTYPE_HEADER;
else
returnTYPE_ITEM;
}
classHeaderArticleViewHolderextendsRecyclerView.ViewHolder{
//轮播的最热新闻图片
@InjectView(R.id.vp_hottest)
ViewPagervpHottest;
//轮播图片下面的小圆点
@InjectView(R.id.ll_hottest_indicator)
LinearLayoutllHottestIndicator;
//学院广播信息
@InjectView(R.id.tv_college_broadcast)
TextViewtvCollegeBroadcast;
publicHeaderArticleViewHolder(ViewitemView){
super(itemView);
ButterKnife.inject(this,itemView);
}
}
classItemArticleViewHolderextendsRecyclerView.ViewHolder{
@InjectView(R.id.rcv_article_photo)
SimpleDraweeViewrcvArticlePhoto;
@InjectView(R.id.rcv_article_title)
TextViewrcvArticleTitle;
@InjectView(R.id.rcv_article_date)
TextViewrcvArticleDate;
@InjectView(R.id.rcv_article_source)
TextViewrcvArticleSource;
@InjectView(R.id.rcv_article_readtimes)
TextViewrcvArticleReadtimes;
@InjectView(R.id.rcv_article_preview)
TextViewrcvArticlePreview;
publicItemArticleViewHolder(ViewitemView){
super(itemView);
ButterKnife.inject(this,itemView);
}
}
}
ItemArticleViewHolder是列表展示的新闻项的ViewHolder,对应了上面的viewholder_article_item.xml。
HeaderArticleViewHolder是头部ViewPager的ViewHolder,对应viewholder_article_header.xml
Note
- 本文上面的ViewPager轮播4幅图片,所以getItemCount()需要复写
- Listheaders=articleList.subList(0,NUM_IMAGE);得到头部图片的数据
- ItemArticlearticle=articleList.get(position+NUM_IMAGE-1);得到下面新闻项的数据
- getItemViewType(intposition)根据position判断是不是头部ViewPager
- onCreateViewHolder(ViewGroupparent,intviewType)根据viewType生成头部图片或者下面新闻项的ViewHolder
二、疑惑及后续计划
除了将ViewPager作为RecyclerView第一项,还有一张方法就是利用ScrollView,大家可以进行研究。
以上就是本文的全部内容,希望对大家的学习有所帮助。