Android項目實戰(zhàn)之仿網(wǎng)易新聞的頁面(RecyclerView )
本文實例實現(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項,也就是 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是覆蓋顯示的,實現(xiàn)在圖片的下方有個小圓點標(biāo)記滑動到了第一張圖片。
新聞項 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實現(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)前頁面的小圓點 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 實現(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項是 ViewPager 占據(jù)了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()); //注意這個閱讀次數(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; //把指示作用的原點圖片加入底部的視圖中 llBottom.addView(mCircleImages[i]); } vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { //圖片左右滑動時候,將當(dāng)前頁的圓點圖片設(shè)為選中狀態(tài) @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); } } //設(shè)置全局變量,currentIndex為選中圖標(biāo)的 index currentIndex = position; } @Override public void onPageScrolled(int i, float v, int i1) { } @Override public void onPageScrollStateChanged(int state) { //實現(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() { //因為多了一個頭部,所以是+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; //學(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是列表展示的新聞項的 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);得到下面新聞項的數(shù)據(jù)
- getItemViewType(int position)根據(jù)position判斷是不是頭部ViewPager
- onCreateViewHolder(ViewGroup parent, int viewType)根據(jù)viewType生成頭部圖片或者下面新聞項的ViewHolder
二、疑惑及后續(xù)計劃
除了將 ViewPager 作為 RecyclerView 第一項,還有一張方法就是利用ScrollView,大家可以進(jìn)行研究。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
- Android中使用RecyclerView實現(xiàn)下拉刷新和上拉加載
- Android中RecyclerView布局代替GridView實現(xiàn)類似支付寶的界面
- Android中RecyclerView實現(xiàn)多級折疊列表效果(二)
- Android中RecyclerView實現(xiàn)橫向滑動代碼
- Android RecyclerView網(wǎng)格布局(支持多種分割線)詳解(2)
- Android Recyclerview實現(xiàn)多選,單選,全選,反選,批量刪除的功能
- Android RecyclerView 復(fù)用錯亂通用解法詳解
- Android RecyclerView實現(xiàn)下拉刷新和上拉加載
- Android RecyclerView的卡頓問題的解決方法
- Android如何利用RecyclerView實現(xiàn)列表倒計時效果實例代碼
相關(guān)文章
Android ListView滑動刪除操作(SwipeListView)
這篇文章主要為大家詳細(xì)介紹了Android ListView滑動刪除操作,主要是學(xué)習(xí)SwipeListView開源框架。感興趣的小伙伴們可以參考一下2016-08-08Android EditText實現(xiàn)輸入金額類型詳解
EditText是Android中一個非常實用的控件,有很多InputType,可以來達(dá)到不同的輸入效果,下面這篇文章主要給大家介紹了關(guān)于Android EditText實現(xiàn)輸入金額類型的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09Android調(diào)試出現(xiàn)The selected device is incompatible問題解決
這篇文章主要介紹了Android調(diào)試出現(xiàn)The selected device is incompatible問題解決的相關(guān)資料,需要的朋友可以參考下2017-01-01Android性能優(yōu)化之利用強(qiáng)大的LeakCanary檢測內(nèi)存泄漏及解決辦法
本篇文章主要介紹了Android性能優(yōu)化之利用LeakCanary檢測內(nèi)存泄漏及解決辦法,有興趣的同學(xué)可以了解一下。2016-11-11