• Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信


    以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3364728.html

    我前两天写过一篇博客《Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信》(http://www.cnblogs.com/tiantianbyconan/p/3360938.html),实现了Tab切换时保留当前Fragment状态,并在切换前自动回调onPause()方法,在切换后自动调用onResume(),这样就做到了跟TahHost一样的功能。

    今天来实现下ViewPager的功能,google提供了一个FragmentPagerAdapter这么一个适配器,蛋疼的是,碰到了跟上次类似的问题。比如ViewPager有5个page,刚打开的时候,会加载page1和page2,我们手动切换到page2的时候,会加载page3,切换到page3的时候,加载page4的同时会destory掉page1,所以,还是面临同样的问题,page的状态无法保存,于是,咱还是自己来实现下好了,自己动手,丰衣足食嘛!(同样 有朋友知道解决办法的话,希望联系我,赐教下哈

    先来看下整个demo的结构,跟上次实现TabHost的例子差不多:

    TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。

    TabAFm.java:

     1 package com.wangjie.fragmentviewpagertest;
     2 
     3 import android.app.Activity;
     4 import android.os.Bundle;
     5 import android.support.v4.app.Fragment;
     6 import android.view.LayoutInflater;
     7 import android.view.View;
     8 import android.view.ViewGroup;
     9 
    10 /**
    11  * Created with IntelliJ IDEA.
    12  * Author: wangjie  email:tiantian.china.2@gmail.com
    13  * Date: 13-6-14
    14  * Time: 下午2:39
    15  */
    16 public class TabAFm extends Fragment{
    17     @Override
    18     public void onAttach(Activity activity) {
    19         super.onAttach(activity);
    20         System.out.println("AAAAAAAAAA____onAttach");
    21     }
    22 
    23     @Override
    24     public void onCreate(Bundle savedInstanceState) {
    25         super.onCreate(savedInstanceState);
    26         System.out.println("AAAAAAAAAA____onCreate");
    27     }
    28 
    29     @Override
    30     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    31         System.out.println("AAAAAAAAAA____onCreateView");
    32         return inflater.inflate(R.layout.tab_a, container, false);
    33     }
    34 
    35     @Override
    36     public void onActivityCreated(Bundle savedInstanceState) {
    37         super.onActivityCreated(savedInstanceState);
    38         System.out.println("AAAAAAAAAA____onActivityCreated");
    39     }
    40 
    41     @Override
    42     public void onStart() {
    43         super.onStart();
    44         System.out.println("AAAAAAAAAA____onStart");
    45     }
    46 
    47     @Override
    48     public void onResume() {
    49         super.onResume();
    50         System.out.println("AAAAAAAAAA____onResume");
    51     }
    52 
    53     @Override
    54     public void onPause() {
    55         super.onPause();
    56         System.out.println("AAAAAAAAAA____onPause");
    57     }
    58 
    59     @Override
    60     public void onStop() {
    61         super.onStop();
    62         System.out.println("AAAAAAAAAA____onStop");
    63     }
    64 
    65     @Override
    66     public void onDestroyView() {
    67         super.onDestroyView();
    68         System.out.println("AAAAAAAAAA____onDestroyView");
    69     }
    70 
    71     @Override
    72     public void onDestroy() {
    73         super.onDestroy();
    74         System.out.println("AAAAAAAAAA____onDestroy");
    75     }
    76 
    77     @Override
    78     public void onDetach() {
    79         super.onDetach();
    80         System.out.println("AAAAAAAAAA____onDetach");
    81     }
    82 }
    View Code

    如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试

    tab_a.xml布局中有个EditText

    其他的Fragment大同小异,这里就不贴出代码了

    现在来看MainActivity:

     1 package com.wangjie.fragmentviewpagertest;
     2 
     3 import android.os.Bundle;
     4 import android.support.v4.app.Fragment;
     5 import android.support.v4.app.FragmentActivity;
     6 import android.support.v4.view.ViewPager;
     7 
     8 import java.util.ArrayList;
     9 import java.util.List;
    10 
    11 public class MainActivity extends FragmentActivity {
    12     private ViewPager viewPager;
    13     public List<Fragment> fragments = new ArrayList<Fragment>();
    14     public String hello = "hello ";
    15 
    16     @Override
    17     public void onCreate(Bundle savedInstanceState) {
    18         super.onCreate(savedInstanceState);
    19         setContentView(R.layout.main);
    20 
    21         fragments.add(new TabAFm());
    22         fragments.add(new TabBFm());
    23         fragments.add(new TabCFm());
    24         fragments.add(new TabDFm());
    25         fragments.add(new TabEFm());
    26 
    27         viewPager = (ViewPager) findViewById(R.id.viewPager);
    28         FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);
    29         adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter.OnExtraPageChangeListener(){
    30             @Override
    31             public void onExtraPageSelected(int i) {
    32                 System.out.println("Extra...i: " + i);
    33             }
    34         });
    35 
    36     }
    37 
    38 }
    View Code

    MainActivity上述代码所示

    MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)

    他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)

    用一个List<Fragment>去维护5个Fragment,也就是5个page。

    MainActivity的布局很简单,就一个ViewPager,main.xml如下:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3               android:orientation="vertical"
     4               android:layout_width="fill_parent"
     5               android:layout_height="fill_parent"
     6         >
     7     <android.support.v4.view.ViewPager
     8         android:id="@+id/viewPager"
     9         android:layout_width="match_parent"
    10         android:layout_height="match_parent"
    11         />
    12 
    13 </LinearLayout>
    View Code

    现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系

    FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);

    现在看下FragmentViewPagerAdapter:

      1 package com.wangjie.fragmentviewpagertest;
      2 
      3 import android.support.v4.app.Fragment;
      4 import android.support.v4.app.FragmentManager;
      5 import android.support.v4.app.FragmentTransaction;
      6 import android.support.v4.view.PagerAdapter;
      7 import android.support.v4.view.ViewPager;
      8 import android.view.View;
      9 import android.view.ViewGroup;
     10 
     11 import java.util.List;
     12 
     13 /**
     14  * 为ViewPager添加布局(Fragment),绑定和处理fragments和viewpager之间的逻辑关系
     15  *
     16  * Created with IntelliJ IDEA.
     17  * Author: wangjie  email:tiantian.china.2@gmail.com
     18  * Date: 13-10-11
     19  * Time: 下午3:03
     20  */
     21 public class FragmentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener{
     22     private List<Fragment> fragments; // 每个Fragment对应一个Page
     23     private FragmentManager fragmentManager;
     24     private ViewPager viewPager; // viewPager对象
     25     private int currentPageIndex = 0; // 当前page索引(切换之前)
     26 
     27     private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口
     28 
     29     public FragmentViewPagerAdapter(FragmentManager fragmentManager, ViewPager viewPager , List<Fragment> fragments) {
     30         this.fragments = fragments;
     31         this.fragmentManager = fragmentManager;
     32         this.viewPager = viewPager;
     33         this.viewPager.setAdapter(this);
     34         this.viewPager.setOnPageChangeListener(this);
     35     }
     36 
     37     @Override
     38     public int getCount() {
     39         return fragments.size();
     40     }
     41 
     42     @Override
     43     public boolean isViewFromObject(View view, Object o) {
     44         return view == o;
     45     }
     46 
     47     @Override
     48     public void destroyItem(ViewGroup container, int position, Object object) {
     49         container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局
     50     }
     51 
     52     @Override
     53     public Object instantiateItem(ViewGroup container, int position) {
     54         Fragment fragment = fragments.get(position);
     55         if(!fragment.isAdded()){ // 如果fragment还没有added
     56             FragmentTransaction ft = fragmentManager.beginTransaction();
     57             ft.add(fragment, fragment.getClass().getSimpleName());
     58             ft.commit();
     59             /**
     60              * 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后
     61              * 会在进程的主线程中,用异步的方式来执行。
     62              * 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。
     63              * 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。
     64              */
     65             fragmentManager.executePendingTransactions();
     66         }
     67 
     68         if(fragment.getView().getParent() == null){
     69             container.addView(fragment.getView()); // 为viewpager增加布局
     70         }
     71 
     72         return fragment.getView();
     73     }
     74 
     75     /**
     76      * 当前page索引(切换之前)
     77      * @return
     78      */
     79     public int getCurrentPageIndex() {
     80         return currentPageIndex;
     81     }
     82 
     83     public OnExtraPageChangeListener getOnExtraPageChangeListener() {
     84         return onExtraPageChangeListener;
     85     }
     86 
     87     /**
     88      * 设置页面切换额外功能监听器
     89      * @param onExtraPageChangeListener
     90      */
     91     public void setOnExtraPageChangeListener(OnExtraPageChangeListener onExtraPageChangeListener) {
     92         this.onExtraPageChangeListener = onExtraPageChangeListener;
     93     }
     94 
     95     @Override
     96     public void onPageScrolled(int i, float v, int i2) {
     97         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
     98             onExtraPageChangeListener.onExtraPageScrolled(i, v, i2);
     99         }
    100     }
    101 
    102     @Override
    103     public void onPageSelected(int i) {
    104         fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()
    105 //        fragments.get(currentPageIndex).onStop(); // 调用切换前Fargment的onStop()
    106         if(fragments.get(i).isAdded()){
    107 //            fragments.get(i).onStart(); // 调用切换后Fargment的onStart()
    108             fragments.get(i).onResume(); // 调用切换后Fargment的onResume()
    109         }
    110         currentPageIndex = i;
    111 
    112         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
    113             onExtraPageChangeListener.onExtraPageSelected(i);
    114         }
    115 
    116     }
    117 
    118     @Override
    119     public void onPageScrollStateChanged(int i) {
    120         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
    121             onExtraPageChangeListener.onExtraPageScrollStateChanged(i);
    122         }
    123     }
    124 
    125 
    126     /**
    127      * page切换额外功能接口
    128      */
    129     static class OnExtraPageChangeListener{
    130         public void onExtraPageScrolled(int i, float v, int i2){}
    131         public void onExtraPageSelected(int i){}
    132         public void onExtraPageScrollStateChanged(int i){}
    133     }
    134 
    135 
    136 }
    View Code

    这里解决Fragment切换重新加载布局的办法,用的是把几个Fragment全部Add,然后根据要显示的哪个Fragment就把哪个Fragment的View给添加到“ViewGroup container”上去。

    效果输出:

    // 以下打开程序后,加载PageA和PageB

    10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onAttach
    10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreate
    10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreateView
    10-12 09:42:46.761: INFO/System.out(27248): AAAAAAAAAA____onActivityCreated
    10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onStart
    10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onResume
    10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onAttach
    10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onCreate
    10-12 09:42:46.851: INFO/System.out(27248): BBBBBBBBBBB____onCreateView
    10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onActivityCreated
    10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onStart
    10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onResume

    // 以下切换到PageB

    10-12 09:42:57.285: INFO/System.out(27248): AAAAAAAAAA____onPause    // 切换到PageB前会调用PageA的onPause()方法
    10-12 09:42:57.285: INFO/System.out(27248): BBBBBBBBBBB____onResume  // 切换到PageB后会调用PageB的onResume()方法
    10-12 09:42:57.285: INFO/System.out(27248): Extra...i: 1            // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
    10-12 09:42:57.582: INFO/System.out(27248): CCCCCCCCCC____onAttach    // 切换到PageB后会加载PageC
    10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreate
    10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreateView
    10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onActivityCreated
    10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onStart
    10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onResume

    // 以下切换到PageC

    10-12 09:43:18.261: INFO/System.out(27248): BBBBBBBBBBB____onPause     // 切换到PageC前会调用PageB的onPause()方法
    10-12 09:43:18.261: INFO/System.out(27248): CCCCCCCCCC____onResume    // 切换到PageC后会调用PageC的onResume()方法
    10-12 09:43:18.261: INFO/System.out(27248): Extra...i: 2              // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
    10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onAttach      // 切换到PageC后会加载PageD
    10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreate
    10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreateView
    10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onActivityCreated
    10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onStart
    10-12 09:43:18.742: INFO/System.out(27248): DDDDDDDDD____onResume

    // 以下切换到PageB
    10-12 09:43:20.742: INFO/System.out(27248): CCCCCCCCCC____onPause      // 切换到PageB前会调用PageC的onPause()方法
    10-12 09:43:20.742: INFO/System.out(27248): BBBBBBBBBBB____onResume    // 切换到PageB后会调用PageB的onResume()方法
    10-12 09:43:20.746: INFO/System.out(27248): Extra...i: 1              // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)

    好了,到此为止,我们已经用Fragment实现了ViewPager的功能了,同样,下面来看下各个Fragment之间的通信

    现在的情况是TabAFm中有个EditText,TabBFm中有个Button,MainActivity中有个变量“hello”

    要做的是,切换到A,输入“I'm PageA”,切换到B,点击Button后,Toast显示“hello I'm PageA”

    MainActivity中没什么好说的,就一个hello变量:

    public String hello = "hello ";

    TabBFm中:

     1 @Override
     2     public void onActivityCreated(Bundle savedInstanceState) {
     3         super.onActivityCreated(savedInstanceState);
     4         System.out.println("BBBBBBBBBBB____onActivityCreated");
     5         this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() {
     6             @Override
     7             public void onClick(View view) {
     8                 // 获得绑定的FragmentActivity
     9                 MainActivity activity = ((MainActivity)getActivity());
    10                 // 获得TabAFm的控件
    11                 EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit);
    12 
    13                 Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();
    14             }
    15         });
    16     }
    View Code

    最终效果图:

    demo下载:http://pan.baidu.com/s/1stGQ7

  • 相关阅读:
    房地产行业的商业智能BusinessIntelligence介绍
    企业混搭应用介绍
    ElasticSearch+NLog+Elmah实现Asp.Net分布式日志管理
    如何寻找“真爱”型合伙人
    微信转发朋友圈小视频就这么简单
    微信 6.5.1 for iOS发布 可以在朋友圈分享相册中的视频
    微信养号教程预防封号
    首场微信小论坛上他们都聊了哪些小程序的议题
    搜狗微信搜索增加平均阅读数和发文数
    微信小程序想要的是无法监测的流量dark social
  • 原文地址:https://www.cnblogs.com/tiantianbyconan/p/3364728.html
Copyright © 2020-2023  润新知