第二種主界面風格則是以網易新聞、鳳凰新聞以及新推出的新浪博客(閱讀版)為代表,使用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:
- <span style="font-family:Comic Sans MS;font-size:18px;"><?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="wrap_content"
- android:background="@color/light_blue"
- android:orientation="horizontal" >
- <ImageView
- android:id="@+id/headIcon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="4dp"
- android:src="@drawable/biz_navigation_tab_news_pressed" />
- <ImageView
- android:id="@+id/headDivider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:src="@drawable/base_action_bar_back_divider" />
- <TextView
- android:id="@+id/headTV"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="4dp"
- android:layout_weight="1"
- android:text="CSDN資訊"
- android:textColor="@color/white"
- android:textSize="21sp"
- android:textStyle="bold">
- </TextView>
- </LinearLayout></span>
為了日后操作上的方便,我將它映射成一個HeadTitlePanel.java文件,可以看到這種寫法跟上篇 上下panel的定義是有點區別的。
- <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.ui;
- import org.yanzi.csdnproject.R;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.widget.ImageView;
- import android.widget.RelativeLayout;
- import android.widget.TextView;
- public class HeadTitlePanel extends RelativeLayout {
- private Context mContext;
- private TextView mHeadTV;
- private ImageView mHeadIcon;
- private ImageView mHeadDivider;
- public HeadTitlePanel(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- mContext = context;
- View parent = LayoutInflater.from(mContext).inflate(R.layout.head_title_panel, this, true);
- mHeadTV = (TextView) parent.findViewById(R.id.headTV);
- }
- }
- </span>
第二步:ViewPager的導航欄
這個本來我是准備自己封裝個的,網上也有用Radiobutton封裝的,考慮到它這個導航欄還是不固定長度可以滑動的,時間原因暫時不封裝了,使用開源Android-ViewPagerIndicator-master.zip 這個包,這個人的github鏈接:https://github.com/JakeWharton 將其中的library文件夾改名ViewPagerIndicator_library導進來。這個里面有好幾種Indicator,我們主要用TabPageIndicator這個。
第三步:MainActivity的布局:
activity_main.xml
- <span style="font-family:Comic Sans MS;font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#eee"
- tools:context=".MainActivity" >
- <org.yanzi.ui.HeadTitlePanel
- android:id="@+id/head_title_panel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true" />
- <com.viewpagerindicator.TabPageIndicator
- android:id="@+id/page_indicator"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/head_title_panel"
- android:background="@color/transparentblue" />
- <android.support.v4.view.ViewPager
- android:id="@+id/view_pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/page_indicator"
- />
- </RelativeLayout></span>
MainActivity.java
- <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.csdnproject;
- import org.yanzi.viewpager.adapter.TabAdapter;
- import com.viewpagerindicator.TabPageIndicator;
- import android.os.Bundle;
- import android.app.Activity;
- import android.app.FragmentManager;
- import android.view.Menu;
- import android.support.v4.app.FragmentActivity;
- import android.support.v4.app.FragmentPagerAdapter;
- import android.support.v4.view.ViewPager;
- public class MainActivity extends FragmentActivity {
- private TabPageIndicator mPageIndicator;
- private ViewPager mViewPager;
- private FragmentPagerAdapter fragPagerAdapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initUI();
- fragPagerAdapter = new TabAdapter(getSupportFragmentManager());
- mViewPager.setAdapter(fragPagerAdapter);
- mPageIndicator.setViewPager(mViewPager, 0);
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- private void initUI(){
- mPageIndicator = (TabPageIndicator)findViewById(R.id.page_indicator);
- mViewPager = (ViewPager)findViewById(R.id.view_pager);
- }
- }
- </span>
出奇的簡單,比單純用Fragment還簡單,原因是只需把Fragment塞到適配器里就ok了,適配器為我們做了Fragment的切換等工作,我們能做的也就是在適配器里new Fragment的時候判斷是否已存在。以下幾點需要注意:
1、在styles.xml里它定義了樣式:
- <span style="font-family:Comic Sans MS;font-size:18px;"> <style name="MyTheme" parent="AppBaseTheme">
- <item name="vpiTabPageIndicatorStyle">@style/MyWidget.TabPageIndicator</item>
- <item name="android:windowBackground">@drawable/init_pic</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:animationDuration">5000</item>
- <item name="android:windowContentOverlay">@null</item>
- </style>
- <style name="MyWidget.TabPageIndicator" parent="Widget">
- <item name="android:gravity">center</item>
- <item name="android:background">@drawable/vpi__tab_indicator</item>
- <item name="android:paddingLeft">22dip</item>
- <item name="android:paddingRight">22dip</item>
- <item name="android:paddingTop">8dp</item>
- <item name="android:paddingBottom">8dp</item>
- <item name="android:textAppearance">@style/MyTextAppearance.TabPageIndicator</item>
- <item name="android:textSize">16sp</item>
- <item name="android:maxLines">1</item>
- </style>
- <style name="MyTextAppearance.TabPageIndicator" parent="Widget">
- <item name="android:textStyle">bold</item>
- <item name="android:textColor">@color/black</item>
- </style></span>
這個是依賴於導進去的包的。
2、它這里用了android:windowBackground的屬性,所以app開啟瞬間會有圖片彈出,之后設置MainActivity的布局背景為android:background="#eee",又把圖片替換了。如果不設android:background="#eee" 會一直看到這個圖片不消失。
3、因為開篇講的原因,MainActivity只能繼承自FragmentActivity。
第四步:MainFragment.java,此類繼承Fragment,且是android.support.v4.app.Fragment下的。
- <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.fragment;
- import org.yanzi.csdnproject.R;
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.TextView;
- public class MainFragment extends Fragment {
- private int mNewsType = 0;
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- View v = inflater.inflate(R.layout.tab_item_fragment_main, null);
- TextView tip = (TextView) v.findViewById(R.id.id_tip);
- Bundle b = getArguments();
- String title = b.getString("TITLES");
- tip.setText(title);
- return v;
- }
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onActivityCreated(savedInstanceState);
- }
- }
- </span>
就是弄了一個布局,然后從中取得參數並顯示。
第五步:ViewPager的適配器TabAdapter.java
- <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.viewpager.adapter;
- import org.yanzi.constant.Constant;
- import org.yanzi.fragment.MainFragment;
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.support.v4.app.FragmentManager;
- import android.support.v4.app.FragmentPagerAdapter;
- public class TabAdapter extends FragmentPagerAdapter {
- public TabAdapter(FragmentManager fm) {
- super(fm);
- // TODO Auto-generated constructor stub
- }
- @Override
- public Fragment getItem(int position) {
- // TODO Auto-generated method stub
- MainFragment fragment = new MainFragment();
- Bundle b = new Bundle();
- String title = Constant.TITLES[position];
- b.putString("TITLES", title);
- fragment.setArguments(b);
- return fragment;
- }
- @Override
- public CharSequence getPageTitle(int position) {
- // TODO Auto-generated method stub
- return Constant.TITLES[position];
- }
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return Constant.TITLES.length;
- }
- }
- </span>
主要是重寫getItem,在這里實例化Fragment,同時設傳遞的參數。其實這里可以通過
- <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