Android應用經典主界面框架之二:仿網易新聞客戶端、CSDN 客戶端 (Fragment ViewPager)


第二種主界面風格則是以網易新聞、鳳凰新聞以及新推出的新浪博客(閱讀版)為代表,使用ViewPager+Fragment,即ViewPager里適配器里放的不是一般的View,而是Fragment。所以適配器不能繼承PagerAdapter,而要繼承FragmentPagerAdapter,這是在android.support.v4.app.FragmentPagerAdapter包里的。有點奇葩的是,FragmentPagerAdapter只在這個包里有,在android.app.*這個包下面么有。到后面會發現,只能用android.support.v4.app.*包下面的東西。兩個包里的FragmentManager是不通用的,而且兩個包里提供的Fragment也不大一樣。如果繼承android.app.*下的Fragment,則不能重新寫構造函數,只能用默認的。v4的包里么有這個限制。

下圖是網易新聞、鳳凰新聞、新浪博客的截圖:

 

關於仿網易新聞客戶端代碼已經很多了,本人主要根據開源的這個CSDN客戶端的制作,准備一步步搞下。這本是一個大牛之作發在oschina上,參考鏈接里分5步去實現。我看了它的代碼,是染在一起的。比如要完這個導航不需要額外的三個包,而他的資源里是弄一起的。所以准備自己玩玩,順便記錄開發中的問題。

第一步:最上面的導航欄

即有“網易新聞”四個大字這一欄。布局文件head_title_panel.xml:

 

[html]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="wrap_content"  
  5.     android:background="@color/light_blue"  
  6.     android:orientation="horizontal" >  
  7.   
  8.     <ImageView  
  9.         android:id="@+id/headIcon"  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:layout_gravity="center_vertical"  
  13.         android:layout_marginLeft="8dp"  
  14.         android:layout_marginRight="4dp"  
  15.         android:src="@drawable/biz_navigation_tab_news_pressed" />  
  16.   
  17.     <ImageView  
  18.         android:id="@+id/headDivider"  
  19.         android:layout_width="wrap_content"  
  20.         android:layout_height="wrap_content"  
  21.         android:layout_gravity="center_vertical"  
  22.         android:layout_marginLeft="4dp"  
  23.         android:layout_marginRight="4dp"  
  24.         android:src="@drawable/base_action_bar_back_divider" />  
  25.   
  26.     <TextView  
  27.         android:id="@+id/headTV"  
  28.         android:layout_width="0dp"  
  29.         android:layout_height="wrap_content"  
  30.         android:layout_gravity="center_vertical"  
  31.         android:layout_marginLeft="4dp"  
  32.         android:layout_weight="1"  
  33.         android:text="CSDN資訊"  
  34.         android:textColor="@color/white"  
  35.         android:textSize="21sp"  
  36.         android:textStyle="bold">  
  37.     </TextView>  
  38.   
  39.   
  40. </LinearLayout></span>  

為了日后操作上的方便,我將它映射成一個HeadTitlePanel.java文件,可以看到這種寫法跟上篇 上下panel的定義是有點區別的。

 

 

[java]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.ui;  
  2.   
  3. import org.yanzi.csdnproject.R;  
  4.   
  5. import android.content.Context;  
  6. import android.util.AttributeSet;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.widget.ImageView;  
  10. import android.widget.RelativeLayout;  
  11. import android.widget.TextView;  
  12.   
  13. public class HeadTitlePanel extends RelativeLayout {  
  14.   
  15.     private Context mContext;  
  16.     private TextView mHeadTV;  
  17.     private ImageView mHeadIcon;  
  18.     private ImageView mHeadDivider;  
  19.       
  20.     public HeadTitlePanel(Context context, AttributeSet attrs) {  
  21.         super(context, attrs);  
  22.         // TODO Auto-generated constructor stub  
  23.         mContext = context;  
  24.         View parent = LayoutInflater.from(mContext).inflate(R.layout.head_title_panel, this, true);  
  25.         mHeadTV = (TextView) parent.findViewById(R.id.headTV);  
  26.     }  
  27.   
  28.       
  29.   
  30. }  
  31. </span>  

 

第二步:ViewPager的導航欄

 

這個本來我是准備自己封裝個的,網上也有用Radiobutton封裝的,考慮到它這個導航欄還是不固定長度可以滑動的,時間原因暫時不封裝了,使用開源Android-ViewPagerIndicator-master.zip 這個包,這個人的github鏈接:https://github.com/JakeWharton 將其中的library文件夾改名ViewPagerIndicator_library導進來。這個里面有好幾種Indicator,我們主要用TabPageIndicator這個。

第三步:MainActivity的布局:

activity_main.xml

 

[html]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#eee"  
  6.     tools:context=".MainActivity" >  
  7.   
  8.     <org.yanzi.ui.HeadTitlePanel  
  9.         android:id="@+id/head_title_panel"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="wrap_content"  
  12.         android:layout_alignParentTop="true" />  
  13.   
  14.     <com.viewpagerindicator.TabPageIndicator  
  15.         android:id="@+id/page_indicator"  
  16.         android:layout_width="match_parent"  
  17.         android:layout_height="wrap_content"  
  18.         android:layout_below="@id/head_title_panel"  
  19.         android:background="@color/transparentblue" />  
  20.   
  21.     <android.support.v4.view.ViewPager  
  22.         android:id="@+id/view_pager"  
  23.         android:layout_width="match_parent"  
  24.         android:layout_height="match_parent"  
  25.         android:layout_below="@id/page_indicator"  
  26.        />  
  27.   
  28. </RelativeLayout></span>  

MainActivity.java

 

 

[java]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.csdnproject;  
  2.   
  3. import org.yanzi.viewpager.adapter.TabAdapter;  
  4.   
  5. import com.viewpagerindicator.TabPageIndicator;  
  6.   
  7. import android.os.Bundle;  
  8. import android.app.Activity;  
  9. import android.app.FragmentManager;  
  10. import android.view.Menu;  
  11. import android.support.v4.app.FragmentActivity;  
  12. import android.support.v4.app.FragmentPagerAdapter;  
  13. import android.support.v4.view.ViewPager;  
  14.   
  15. public class MainActivity extends FragmentActivity {  
  16. private TabPageIndicator mPageIndicator;  
  17. private ViewPager mViewPager;  
  18. private FragmentPagerAdapter fragPagerAdapter;  
  19.   
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState) {  
  22.         super.onCreate(savedInstanceState);  
  23.         setContentView(R.layout.activity_main);  
  24.         initUI();  
  25.           
  26.         fragPagerAdapter = new TabAdapter(getSupportFragmentManager());  
  27.         mViewPager.setAdapter(fragPagerAdapter);  
  28.         mPageIndicator.setViewPager(mViewPager, 0);  
  29.           
  30.           
  31.     }  
  32.   
  33.     @Override  
  34.     public boolean onCreateOptionsMenu(Menu menu) {  
  35.         // Inflate the menu; this adds items to the action bar if it is present.  
  36.         getMenuInflater().inflate(R.menu.main, menu);  
  37.         return true;  
  38.     }  
  39.     private void initUI(){  
  40.         mPageIndicator = (TabPageIndicator)findViewById(R.id.page_indicator);  
  41.         mViewPager = (ViewPager)findViewById(R.id.view_pager);  
  42.     }  
  43.   
  44. }  
  45. </span>  


出奇的簡單,比單純用Fragment還簡單,原因是只需把Fragment塞到適配器里就ok了,適配器為我們做了Fragment的切換等工作,我們能做的也就是在適配器里new Fragment的時候判斷是否已存在。以下幾點需要注意:

 

1、在styles.xml里它定義了樣式:

 

[html]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;">    <style name="MyTheme" parent="AppBaseTheme">  
  2.         <item name="vpiTabPageIndicatorStyle">@style/MyWidget.TabPageIndicator</item>  
  3.         <item name="android:windowBackground">@drawable/init_pic</item>  
  4.         <item name="android:windowNoTitle">true</item>  
  5.         <item name="android:animationDuration">5000</item>  
  6.         <item name="android:windowContentOverlay">@null</item>  
  7.     </style>  
  8.     <style name="MyWidget.TabPageIndicator" parent="Widget">  
  9.         <item name="android:gravity">center</item>  
  10.         <item name="android:background">@drawable/vpi__tab_indicator</item>  
  11.         <item name="android:paddingLeft">22dip</item>  
  12.         <item name="android:paddingRight">22dip</item>  
  13.         <item name="android:paddingTop">8dp</item>  
  14.         <item name="android:paddingBottom">8dp</item>  
  15.         <item name="android:textAppearance">@style/MyTextAppearance.TabPageIndicator</item>  
  16.         <item name="android:textSize">16sp</item>  
  17.         <item name="android:maxLines">1</item>  
  18.     </style>  
  19.   
  20.     <style name="MyTextAppearance.TabPageIndicator" parent="Widget">  
  21.         <item name="android:textStyle">bold</item>  
  22.         <item name="android:textColor">@color/black</item>  
  23.     </style></span>  


這個是依賴於導進去的包的。

 

2、它這里用了android:windowBackground的屬性,所以app開啟瞬間會有圖片彈出,之后設置MainActivity的布局背景為android:background="#eee",又把圖片替換了。如果不設android:background="#eee" 會一直看到這個圖片不消失。

3、因為開篇講的原因,MainActivity只能繼承自FragmentActivity。

第四步:MainFragment.java,此類繼承Fragment,且是android.support.v4.app.Fragment下的。

 

[java]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.fragment;  
  2.   
  3. import org.yanzi.csdnproject.R;  
  4.   
  5. import android.os.Bundle;  
  6. import android.support.v4.app.Fragment;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.view.ViewGroup;  
  10. import android.widget.TextView;  
  11.   
  12. public class MainFragment extends Fragment {  
  13.     private int mNewsType = 0;  
  14.   
  15.     @Override  
  16.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  17.             Bundle savedInstanceState) {  
  18.         // TODO Auto-generated method stub  
  19.         View v = inflater.inflate(R.layout.tab_item_fragment_main, null);  
  20.         TextView tip = (TextView) v.findViewById(R.id.id_tip);  
  21.         Bundle b = getArguments();  
  22.         String title = b.getString("TITLES");  
  23.         tip.setText(title);  
  24.         return v;  
  25.     }  
  26.     @Override  
  27.     public void onActivityCreated(Bundle savedInstanceState) {  
  28.         // TODO Auto-generated method stub  
  29.         super.onActivityCreated(savedInstanceState);  
  30.     }  
  31.       
  32.   
  33. }  
  34. </span>  

就是弄了一個布局,然后從中取得參數並顯示。

 

第五步:ViewPager的適配器TabAdapter.java

 

[java]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.viewpager.adapter;  
  2.   
  3. import org.yanzi.constant.Constant;  
  4. import org.yanzi.fragment.MainFragment;  
  5.   
  6. import android.os.Bundle;  
  7. import android.support.v4.app.Fragment;  
  8. import android.support.v4.app.FragmentManager;  
  9. import android.support.v4.app.FragmentPagerAdapter;  
  10.   
  11. public class TabAdapter extends FragmentPagerAdapter {  
  12.   
  13.     public TabAdapter(FragmentManager fm) {  
  14.           
  15.         super(fm);  
  16.         // TODO Auto-generated constructor stub  
  17.     }  
  18.   
  19.     @Override  
  20.     public Fragment getItem(int position) {  
  21.         // TODO Auto-generated method stub  
  22.         MainFragment fragment = new MainFragment();  
  23.         Bundle b = new Bundle();  
  24.         String title = Constant.TITLES[position];  
  25.         b.putString("TITLES", title);  
  26.         fragment.setArguments(b);  
  27.         return fragment;  
  28.     }  
  29.   
  30.     @Override  
  31.     public CharSequence getPageTitle(int position) {  
  32.         // TODO Auto-generated method stub  
  33.         return Constant.TITLES[position];  
  34.     }  
  35.   
  36.     @Override  
  37.     public int getCount() {  
  38.         // TODO Auto-generated method stub  
  39.         return Constant.TITLES.length;  
  40.     }  
  41.   
  42. }  
  43. </span>  


主要是重寫getItem,在這里實例化Fragment,同時設傳遞的參數。其實這里可以通過

[java]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. <span style="font-family:Comic Sans MS;font-size:18px;">FragmentManager</span>  

按照Tag查找對應的Fragment是否存在,再進行實例化。

 

另外,getPageTitle這個接口必須重寫,其實看TabPageIndicator.java這個類的實現可以發現,它需要傳進去一個ViewPager,然后獲得適配器,從適配器里得到Title。因為用了這個開源包,不能再用ViewPager的setOnPageChangeListener接口,只能用mPageIndicator.setOnPageChangeListener(listener)進行監聽。

完畢,源碼鏈接:鏈接:http://pan.baidu.com/s/1bn4EFbp 密碼:dx4s

效果如下:

 

 

 

 http://blog.csdn.net/yanzi1225627/article/details/31462007#comments


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM