Android項(xiàng)目實(shí)戰(zhàn)之仿網(wǎng)易新聞的頁面(RecyclerView )
本文實(shí)例實(shí)現(xiàn)一個仿網(wǎng)易新聞的頁面,上面是輪播的圖片,下面是 RecyclerView 顯示新聞列表,具體內(nèi)容如下
錯誤方法
<?xml version="1.0" encoding="utf-8"?> <LinearLayout ...> <ViewPager ... /> <android.support.v7.widget.RecyclerView .../> </LinearLayout>
這樣布局 ViewPager 在 RecyclerView 的上面,如果不做特殊處理,當(dāng)下滑 RecyclerView 加載更多內(nèi)容的時候,ViewPager會固定不動。
正確的效果是下滑加載更多的時候,ViewPager 會滑出頁面,釋放空間供其他內(nèi)容展示。
一、解決思路
方法有兩種
- ViewPager作為 RecyclerView 的第0項(xiàng),也就是 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是覆蓋顯示的,實(shí)現(xiàn)在圖片的下方有個小圓點(diǎn)標(biāo)記滑動到了第一張圖片。
新聞項(xiàng) 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="關(guān)于舉辦《經(jīng)典音樂作品欣賞與人文審美》講座的通知"
android:textColor="@color/primary_text" />
<!-- 新聞 發(fā)布時間 來源 閱讀次數(shù)-->
<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="科學(xué)研究院" />
<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="講座主要內(nèi)容:以中、西方音樂歷史中經(jīng)典音樂作品為基礎(chǔ),通過作曲家及作品創(chuàng)作背景、相關(guān)音樂文化史知識及音樂欣賞常識..." />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
這篇文章 Android Material Design學(xué)習(xí)之RecyclerView代替 ListView sscc實(shí)現(xiàn)了不加 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 用到的參數(shù)值
private static final int UPTATE_VIEWPAGER = 0;
//新聞列表
private List<ItemArticle> articleList;
//設(shè)置當(dāng)前 第幾個圖片 被選中
private int currentIndex = 0;
//context
private Context context;
private LayoutInflater mLayoutInflater;
private ImageView[] mCircleImages;//底部只是當(dāng)前頁面的小圓點(diǎn)
public ArticleAdapter(Context context, List<ItemArticle> articleList) {
this.context = context;
//頭部viewpager圖片固定是7張,剩下的是列表的數(shù)據(jù)
this.articleList = articleList;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//理論上應(yīng)該把最可能返回的 TYPE 放在前面
View view = null;
if (viewType == TYPE_ITEM) {
view = mLayoutInflater.inflate(
R.layout.viewholder_article_item, parent, false);
return new ItemArticleViewHolder(view);
}
//頭部返回 ViewPager 實(shí)現(xiàn)的輪播圖片
if (viewType == TYPE_HEADER) {
view = mLayoutInflater.inflate(
R.layout.viewholder_article_header, parent, false);
return new HeaderArticleViewHolder(view);
}
return null;
// //可以拋出異常,沒有對應(yīng)的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) {
//轉(zhuǎn)型
ItemArticleViewHolder newHolder = (ItemArticleViewHolder) holder;
//注意RecyclerView第0項(xiàng)是 ViewPager 占據(jù)了0 1 2 3圖片
//那么下面的列表展示是 RecyclerView 的第1項(xiàng),從第4項(xiàng)開始
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());
//注意這個閱讀次數(shù)是 int 類型,需要轉(zhuǎn)化為 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 里面嵌套設(shè)置 Adapter 是否優(yōu)雅?
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 當(dāng)從末頁調(diào)到首頁是,不顯示翻頁動畫效果,
vp.setCurrentItem(msg.arg1, false);
}
break;
}
}
};
//下面是設(shè)置動畫切換的樣式
vp.setPageTransformer(true, new RotateUpTransformer());
//創(chuàng)建底部指示位置的導(dǎo)航欄
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;
//把指示作用的原點(diǎn)圖片加入底部的視圖中
llBottom.addView(mCircleImages[i]);
}
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
//圖片左右滑動時候,將當(dāng)前頁的圓點(diǎn)圖片設(shè)為選中狀態(tài)
@Override
public void onPageSelected(int position) {
// 一定幾個圖片,幾個圓點(diǎn),但注意是從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);
}
}
//設(shè)置全局變量,currentIndex為選中圖標(biāo)的 index
currentIndex = position;
}
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageScrollStateChanged(int state) {
//實(shí)現(xiàn)切換到末尾后返回到第一張
switch (state) {
// 手勢滑動
case ViewPager.SCROLL_STATE_DRAGGING:
break;
// 界面切換中
case ViewPager.SCROLL_STATE_SETTLING:
break;
case ViewPager.SCROLL_STATE_IDLE:// 滑動結(jié)束,即切換完畢或者加載完畢
// 當(dāng)前為最后一張,此時從右向左滑,則切換到第一張
if (vp.getCurrentItem() == vp.getAdapter()
.getCount() - 1) {
vp.setCurrentItem(0, false);
}
// 當(dāng)前為第一張,此時從左向右滑,則切換到最后一張
else if (vp.getCurrentItem() == 0) {
vp.setCurrentItem(vp.getAdapter()
.getCount() - 1, false);
}
break;
default:
break;
}
}
});
//設(shè)置自動輪播圖片,5s后執(zhí)行,周期是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() {
//因?yàn)槎嗔艘粋€頭部,所以是+1,但是頭部 ViewPager 占了7個
//所以實(shí)際是少了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;
//輪播圖片下面的小圓點(diǎn)
@InjectView(R.id.ll_hottest_indicator)
LinearLayout llHottestIndicator;
//學(xué)院廣播信息
@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是列表展示的新聞項(xiàng)的 ViewHolder,對應(yīng)了上面的 viewholder_article_item.xml。
HeaderArticleViewHolder 是頭部 ViewPager 的 ViewHolder, 對應(yīng)viewholder_article_header.xml
Note
- 本文上面的 ViewPager 輪播4幅圖片,所以getItemCount()需要復(fù)寫
- List headers = articleList.subList(0, NUM_IMAGE );得到頭部圖片的數(shù)據(jù)
- ItemArticle article = articleList.get(position + NUM_IMAGE - 1);得到下面新聞項(xiàng)的數(shù)據(jù)
- getItemViewType(int position)根據(jù)position判斷是不是頭部ViewPager
- onCreateViewHolder(ViewGroup parent, int viewType)根據(jù)viewType生成頭部圖片或者下面新聞項(xiàng)的ViewHolder
二、疑惑及后續(xù)計(jì)劃
除了將 ViewPager 作為 RecyclerView 第一項(xiàng),還有一張方法就是利用ScrollView,大家可以進(jìn)行研究。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
- Android中使用RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載
- Android中RecyclerView布局代替GridView實(shí)現(xiàn)類似支付寶的界面
- Android中RecyclerView實(shí)現(xiàn)多級折疊列表效果(二)
- Android中RecyclerView實(shí)現(xiàn)橫向滑動代碼
- Android RecyclerView網(wǎng)格布局(支持多種分割線)詳解(2)
- Android Recyclerview實(shí)現(xiàn)多選,單選,全選,反選,批量刪除的功能
- Android RecyclerView 復(fù)用錯亂通用解法詳解
- Android RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載
- Android RecyclerView的卡頓問題的解決方法
- Android如何利用RecyclerView實(shí)現(xiàn)列表倒計(jì)時效果實(shí)例代碼
相關(guān)文章
Android ListView滑動刪除操作(SwipeListView)
這篇文章主要為大家詳細(xì)介紹了Android ListView滑動刪除操作,主要是學(xué)習(xí)SwipeListView開源框架。感興趣的小伙伴們可以參考一下2016-08-08
Android創(chuàng)建Menu菜單實(shí)例
這篇文章主要介紹了Android創(chuàng)建Menu菜單實(shí)例,講述了Android菜單項(xiàng)的創(chuàng)建方法,在Android應(yīng)用程序開發(fā)中非常具有實(shí)用價值,需要的朋友可以參考下2014-10-10
Android EditText實(shí)現(xiàn)輸入金額類型詳解
EditText是Android中一個非常實(shí)用的控件,有很多InputType,可以來達(dá)到不同的輸入效果,下面這篇文章主要給大家介紹了關(guān)于Android EditText實(shí)現(xiàn)輸入金額類型的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09
Android調(diào)試出現(xiàn)The selected device is incompatible問題解決
這篇文章主要介紹了Android調(diào)試出現(xiàn)The selected device is incompatible問題解決的相關(guān)資料,需要的朋友可以參考下2017-01-01
Android性能優(yōu)化之利用強(qiáng)大的LeakCanary檢測內(nèi)存泄漏及解決辦法
本篇文章主要介紹了Android性能優(yōu)化之利用LeakCanary檢測內(nèi)存泄漏及解決辦法,有興趣的同學(xué)可以了解一下。2016-11-11

