一、概述

ViewPager是android-support-v4中提供的类,它是一个容器类,常用于页面之间的切换。

继上篇文章《ViewPager之引导页》之后,本文主要介绍ViewPager更为通用的实践:ViewPager搭配Fragment实现页面切换。

这种实现方式相对于上篇文章而言,可以更好的支持不同页面各自的复杂逻辑,与此同时,也能够保障页面之间的耦合度尽可能的低。

按照惯例,先晒出效果图:

ViewPager之Fragment页面切换   ViewPager之Fragment页面切换   ViewPager之Fragment页面切换

 

二、实现思路

首先分析一下不同区域的交互需求:

中间灰色区域除了要支持三套完全不同的逻辑之外,还要支持左右滑动切换。而顶部ActionBar和底部Tab切换都只需要更新状态,无需整体变换,也不需要整体滑动;

因此,中间灰色区域用ViewPager实现,它包含三个Fragment子页面。而顶部ActionBar和底部Tab切换各自是一个Fragment,直接隶属于Activity。

然后解决不同Fragment之间的依赖关系:

五个Fragment之间沟通的唯一纽带就是ViewPager页面的切换,因此,ViewPager页面切换时通知到不同的Fragment即可。

 [转载请保留本文地址:http://www.cnblogs.com/snser/p/5700754.html] 

三、开始干活

3.1 搭建整体框架

本文的五个Fragment采用三种方式载入:

ViewPager中的三个Fragment自然是通过其Adatper进行载入,顶部的TitleFragment(ActionBar)直接声明在layout布局中,而底部的TabFragment采用动态载入。

这样做的目的是方便后续分析不同载入方式的实际载入实际。

ok,整体的layout布局自然也就成了下面的样子:

viewpager_fragment.xml(activity的布局): 

 1 <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="@color/background_default"
 6     tools:context="${relativePackage}.${activityClass}" >
 7     
 8     <fragment
 9         android:id="@+id/viewpager_fragment_title"
10         android:name="cc.snser.cnblog5700754.TitleFragment"
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content"
13         android:layout_alignParentTop="true" />
14 
15     <android.support.v4.view.ViewPager
16         android:id="@+id/viewpager_fragment_pager"
17         android:layout_width="match_parent"
18         android:layout_height="match_parent"
19         android:layout_above="@+id/viewpager_fragment_container"
20         android:layout_below="@+id/viewpager_fragment_title" />
21     
22     <FrameLayout
23         android:id="@id/viewpager_fragment_container"
24         android:layout_width="match_parent"
25         android:layout_height="wrap_content"
26         android:layout_alignParentBottom="true" >
27     </FrameLayout>
28     
29 </RelativeLayout>

对应的,主界面的逻辑如下:

ViewPagerFragmentActivity.java:

  1 public class ViewPagerFragmentActivity extends FragmentActivity {
  2     private FragmentManager mManager = getSupportFragmentManager();
  3     
  4     private TitleFragment mTitleFragment;
  5     private TabFragment mTabFragment;
  6     private ViewPager mPager;
  7     
  8     private ViewPagerAdapter mAdapter;
  9     
 10     private static final int DEFAULT_PAGE = 1; //默认页面
 11     
 12     @Override
 13     protected void onCreate(Bundle savedInstanceState) {
 14         Log.d("Snser", "ViewPagerFragmentActivity onCreate");
 15         super.onCreate(savedInstanceState);
 16         Log.d("Snser", "ViewPagerFragmentActivity onCreate setContentView");
 17         setContentView(R.layout.viewpager_fragment);
 18         Log.d("Snser", "ViewPagerFragmentActivity onCreate initView");
 19         initView();
 20     }
 21     
 22     private void initView() {
 23         mTitleFragment = (TitleFragment)mManager.findFragmentById(R.id.viewpager_fragment_title);
 24         mTabFragment = new TabFragment();
 25         mTabFragment.setOnTabClickListenser(new ViewPageTabClickListenser());
 26         mManager.beginTransaction().replace(R.id.viewpager_fragment_container, mTabFragment).commit();
 27         mPager = (ViewPager)findViewById(R.id.viewpager_fragment_pager);
 28         mPager.setAdapter(mAdapter = new ViewPagerAdapter(mManager));
 29         mPager.setOnPageChangeListener(new ViewPageChangeListener());
 30         setCurrentItem(DEFAULT_PAGE);
 31     }
 32     
 33     @Override
 34     protected void onResume() {
 35         Log.d("Snser", "ViewPagerFragmentActivity onResume");
 36         super.onResume();
 37     }
 38     
 39     private class ViewPageChangeListener implements OnPageChangeListener {
 40         @Override
 41         public void onPageSelected(int position) {
 42             setCurrentItem(position);
 43         }
 44         
 45         @Override
 46         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 47         }
 48         
 49         @Override
 50         public void onPageScrollStateChanged(int state) {
 51         }
 52     }
 53     
 54     private class ViewPagerAdapter extends FragmentPagerAdapter {
 55         private ArrayList<PagerFragment> mFragments = new ArrayList<PagerFragment>();
 56         
 57         public ViewPagerAdapter(FragmentManager fm) {
 58             super(fm);
 59             mFragments.add(new ClickFragment());
 60             mFragments.add(new DateFragment());
 61             mFragments.add(new AnimFragment());
 62         }
 63 
 64         @Override
 65         public Fragment getItem(int position) {
 66             return mFragments.get(position);
 67         }
 68 
 69         @Override
 70         public int getCount() {
 71             return mFragments.size();
 72         }
 73     }
 74     
 75     private class ViewPageTabClickListenser implements OnTabClickListenser {
 76         @Override
 77         public void onTabClick(int tab) {
 78             setCurrentItem(tab);
 79         }
 80     }
 81        
 82     private void setCurrentItem(int item) {
 83         if (item == mPager.getCurrentItem()) {
 84             //此时是源于initView或onPageSelected的调用
 85             notifyPageChangeToFragments(item);
 86         } else {
 87             //此时是源于initView或onTabClick的调用,后续会自动触发一次onPageSelected
 88             mPager.setCurrentItem(item);
 89         }
 90     }
 91     
 92     private void notifyPageChangeToFragments(int item) {
 93         for (int page = 0; page != mAdapter.getCount(); ++page) {
 94             final Fragment fragment = mAdapter.getItem(page);
 95             if (fragment instanceof PagerFragment) {
 96                 if (page == item) {
 97                     ((PagerFragment)fragment).onPageIn();
 98                 } else {
 99                     ((PagerFragment)fragment).onPageOut();
100                 }
101             }
102         }
103         mTitleFragment.setCurrentTab(item);
104         mTabFragment.setCurrentTab(item);
105     }
106 }

可以看到,包含三种完全不同功能的Activity,其主界面代码居然只有区区106行,这甚至比上篇文章《ViewPager之引导页》还要少。

这必须要归功于Fragment的使用。

三个页面的具体逻辑分别由DateFragment、ClickFragment、AnimFragment进行维护,而ViewPager要做的,只是进行Fragment的切换和通知。

具体来说,ViewPagerAdapter负责根据不同的postion取出不同的Fragment。而三个页面Fragment都继承自PagerFragment:

PagerFragment.java: 

1 public class PagerFragment extends Fragment{
2     
3     public void onPageIn() {
4     }
5     
6     public void onPageOut() {
7     }
8     
9 }

亦即在页面切换的时候(不管是来自滑动还是点击tab),activity都会通知三个fragment它们各自是否可见。

同时,在 notifyPageChangeToFragments 方法中,也会通知TitleFragment和TabFragment,它们该切换状态了。

3.2 Fragment的各自实现

拿AnimFragment举例,这个动画Fragment的功能是在其切入(onPageIn)的时候播放淡入的动画,而在其切出(onPageOut)的时候销毁动画。 

 1 public class AnimFragment extends PagerFragment {
 2     private View mViewRoot;
 3     private ImageView mImg;
 4     
 5     private Animation mAnim;
 6     
 7     @Override
 8     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 9         Log.d("Snser", "AnimFragment onCreateView");
10         mViewRoot = inflater.inflate(R.layout.viewpager_fragment_anim, container, false);
11         mAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_fade_in);
12         mAnim.setInterpolator(new LinearInterpolator());
13         initView(mViewRoot);
14         return mViewRoot;
15     }
16     
17     private void initView(View root) {
18         mImg = (ImageView)root.findViewById(R.id.viewpager_fragment_anim_img);
19         startAnim();
20     }
21     
22     @Override
23     public void onDestroy() {
24         super.onDestroy();
25         stopAnim();
26     }
27     
28     @Override
29     public void onPageIn() {
30         super.onPageIn();
31         startAnim();
32     }
33     
34     @Override
35     public void onPageOut() {
36         super.onPageOut();
37         stopAnim();
38     }
39     
40     private void startAnim() {
41         if (mImg != null && mAnim != null) {
42             mImg.startAnimation(mAnim);
43         }
44     }
45     
46     private void stopAnim() {
47         if (mImg != null && mAnim != null) {
48             mImg.clearAnimation();
49         }
50     }
51     
52 }

DateFragment的作用是在切入的时候刷新当前日期和时间:

DateFragment.java:

 1 public class DateFragment extends PagerFragment {
 2 
 3     private View mViewRoot;
 4     private TextView mTxtDate;
 5     
 6     private SimpleDateFormat mFormat = new SimpleDateFormat("yyyy/MM/dd\nHH:mm:ss", Locale.CHINA);
 7     
 8     @Override
 9     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
10         Log.d("Snser", "DateFragment onCreateView");
11         mViewRoot = inflater.inflate(R.layout.viewpager_fragment_date, container, false);
12         initView(mViewRoot);
13         return mViewRoot;
14     }
15     
16     @Override
17     public void onPageIn() {
18         super.onPageIn();
19         refreshDate();
20     }
21     
22     private void initView(View root) {
23         mTxtDate = (TextView)root.findViewById(R.id.viewpager_fragment_date_txt);
24         refreshDate();
25     }
26     
27     private void refreshDate() {
28         if (mTxtDate != null) {
29             mTxtDate.setText(mFormat.format(new Date()));
30         }
31     }
32     
33 }
View Code

相关文章: