zoukankan      html  css  js  c++  java
  • Android -- ViewPager、Fragment、状态保存、通信

    工程架构                                                                                     

    image

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

    TabAFm.java                                                                           

    package com.yydcdut.viewpagerstudy;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class TabAFm extends Fragment {
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            System.out.println("AAAAAAAAAA____onAttach");
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            System.out.println("AAAAAAAAAA____onCreate");
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            System.out.println("AAAAAAAAAA____onCreateView");
            return inflater.inflate(R.layout.tab_a, container, false);
        }
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            System.out.println("AAAAAAAAAA____onActivityCreated");
        }
    
        @Override
        public void onStart() {
            super.onStart();
            System.out.println("AAAAAAAAAA____onStart");
        }
    
        @Override
        public void onResume() {
            super.onResume();
            System.out.println("AAAAAAAAAA____onResume");
        }
    
        @Override
        public void onPause() {
            super.onPause();
            System.out.println("AAAAAAAAAA____onPause");
        }
    
        @Override
        public void onStop() {
            super.onStop();
            System.out.println("AAAAAAAAAA____onStop");
        }
    
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            System.out.println("AAAAAAAAAA____onDestroyView");
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            System.out.println("AAAAAAAAAA____onDestroy");
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            System.out.println("AAAAAAAAAA____onDetach");
        }
        
    }

    如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试。tab_a.xml布局中有个EditText,其他的Fragment大同小异,这里就不贴出代码了

    MainActivity                                                                             

    package com.yydcdut.viewpagerstudy;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.view.ViewPager;
    
    public class MainActivity extends FragmentActivity {
    
        private ViewPager viewPager;
        public List<Fragment> fragments = new ArrayList<Fragment>();
        public String hello = "hello ";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            fragments.add(new TabAFm());
            fragments.add(new TabBFm());
            fragments.add(new TabCFm());
            fragments.add(new TabDFm());
            fragments.add(new TabEFm());
    
            viewPager = (ViewPager) findViewById(R.id.viewPager);
    
            FragmentViewPagerAdapter2 adapter = new FragmentViewPagerAdapter2(this.getSupportFragmentManager(), viewPager,fragments);
    
            adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter2.OnExtraPageChangeListener(){
                @Override
                public void onExtraPageSelected(int i) {
                    System.out.println("Extra...i: " + i);
                }
                @Override
                public void onExtraPageScrolled(int i, float v, int i2) {
                    
                    super.onExtraPageScrolled(i, v, i2);
                }
                @Override
                public void onExtraPageScrollStateChanged(int i) {
                
                    super.onExtraPageScrollStateChanged(i);
                }                        
            });
        }
    }

    MainActivity上述代码所示

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

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

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

    activity_main.xml                                                                   

    <LinearLayout 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:orientation="vertical"
        tools:context=".MainActivity" >
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>

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

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

    FragmentViewPagerAdapter2                                                

    package com.yydcdut.viewpagerstudy;
    
    import java.util.List;
    
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v4.view.ViewPager.OnPageChangeListener;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class FragmentViewPagerAdapter2 {
        private List<Fragment> fragments; // 每个Fragment对应一个Page
        private FragmentManager fragmentManager;
        private ViewPager viewPager; // viewPager对象
        private int currentPageIndex = 0; // 当前page索引(切换之前)
        private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口
    
        /**
         * 构造函数
         * 
         * @param fragmentManager
         * @param viewPager
         * @param fragments
         */
        public FragmentViewPagerAdapter2(FragmentManager fragmentManager,
                ViewPager viewPager, List<Fragment> fragments) {
            this.fragments = fragments;
            this.fragmentManager = fragmentManager;
            this.viewPager = viewPager;
            // PagerAdapter
            MyPagerAdapter myPagerAdapter = new MyPagerAdapter();
            this.viewPager.setAdapter(myPagerAdapter);
            // PageChangeListener
            MyPageChangeListener myPageChangeListener = new MyPageChangeListener();
            this.viewPager.setOnPageChangeListener(myPageChangeListener);
        }
    
        /**
         * 当前page索引(切换之前)
         * 
         * @return
         */
        public int getCurrentPageIndex() {
            return currentPageIndex;
        }
    
        /**
         * PagerAdapter 要使用PagerAdapter,首先要继承PagerAdapter类,然后至少覆盖以下方法
         * instantiateItem(ViewGroup,
         * int)【这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象放在当前的ViewPager中】
         * destroyItem(ViewGroup, int, Object)【这个方法,是从ViewGroup中移出当前View】
         * getCount()【这个方法,是获取当前窗体界面数】 isViewFromObject(View, Object)
         * 【这个方法,在帮助文档中原文是could be implemented as return view ==
         * object,也就是用于判断是否由对象生成界面】
         * 
         * @author sansung
         * 
         */
        class MyPagerAdapter extends PagerAdapter {
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                Fragment fragment = fragments.get(position);// 取得位置,获取出来Fragment
                if (!fragment.isAdded()) { // 如果fragment还没有added
                    FragmentTransaction ft = fragmentManager.beginTransaction();
                    ft.add(fragment, fragment.getClass().getSimpleName());
                    ft.commit();
                    /**
                     * 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后
                     * 会在进程的主线程中,用异步的方式来执行。 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。
                     * 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。
                     */
                    fragmentManager.executePendingTransactions();
                }
    
                if (fragment.getView().getParent() == null) {
                    container.addView(fragment.getView()); // 为viewpager增加布局
                }
    
                return fragment.getView();
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局
            }
    
            @Override
            public int getCount() {
                return fragments.size();
            }
    
            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }
    
        }
    
        /**
         * OnPageChangeListener
         * 
         * @author sansung
         * 
         */
        class MyPageChangeListener implements OnPageChangeListener {
            /**
             * 此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。 arg0
             * ==1的时辰默示正在滑动,arg0==2的时辰默示滑动完毕了,arg0==0的时辰默示什么都没做。
             */
            @Override
            public void onPageScrollStateChanged(int arg0) {
                if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口
                    onExtraPageChangeListener.onExtraPageScrollStateChanged(arg0);
                }
            }
    
            /**
             * 当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。 其中三个参数的含义分别为: arg0
             * :当前页面,及你点击滑动的页面 arg1:当前页面偏移的百分比 arg2:当前页面偏移的像素位置
             */
            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口
                    onExtraPageChangeListener.onExtraPageScrolled(arg0, arg1, arg2);
                }
            }
    
            /**
             * 此方法是页面跳转完后得到调用,arg0是你当前选中的页面的Position(位置编号)。
             */
            @Override
            public void onPageSelected(int arg0) {
                fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()
                // fragments.get(currentPageIndex).onStop(); //
                // 调用切换前Fargment的onStop()
                if (fragments.get(arg0).isAdded()) {
                    // fragments.get(i).onStart(); // 调用切换后Fargment的onStart()
                    fragments.get(arg0).onResume(); // 调用切换后Fargment的onResume()
                }
                
                currentPageIndex = arg0;
                
                if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口
                    onExtraPageChangeListener.onExtraPageSelected(arg0);
                }
            }
        }
    
        /**
         * page切换额外功能接口
         */
        static class OnExtraPageChangeListener {
            public void onExtraPageScrolled(int i, float v, int i2) {
            }
    
            public void onExtraPageSelected(int i) {
            }
    
            public void onExtraPageScrollStateChanged(int i) {
            }
        }
    
        /**
         * 得到页面切换额外功能监听器
         * 
         * @return onExtraPageChangeListener
         */
        public OnExtraPageChangeListener getOnExtraPageChangeListener() {
            return onExtraPageChangeListener;
        }
    
        /**
         * 设置页面切换额外功能监听器
         * 
         * @param onExtraPageChangeListener
         */
        public void setOnExtraPageChangeListener(
                OnExtraPageChangeListener onExtraPageChangeListener) {
            this.onExtraPageChangeListener = onExtraPageChangeListener;
        }
    
    }

    这里解决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之间的通信                                                                   

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

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

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

    public String hello = "hello ";

    TabBFm.java:

    @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            System.out.println("BBBBBBBBBB____onActivityCreated");
            this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() {
                              @Override
                              public void onClick(View view) {
                                  // 获得绑定的FragmentActivity
                                  MainActivity activity = ((MainActivity)getActivity());
                                 // 获得TabAFm的控件
                                EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit);
                 
                                Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();
                             }
                         });
        }

    PagerAdapter                                                                           

    PageAdapter是一个抽象类,直接继承于Object,导入包android.support.v4.view.PagerAdapter即可使用。

    关于PageAapter的描述,原文是这样的:Base class providing the adapter to populate pages inside of a ViewPager.  You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter or FragmentStatePagerAdapter。

    其实PagerAdapter就是ViewPager提供的一个适配器,方便我们对各个View进行控制。那ViewPager又是什么呢?它是实现左右两个屏幕平滑地切换的一个类,具体的自己百度google…关于ViewPager的用法好多。

    要使用PagerAdapter,首先要继承PagerAdapter类,然后至少覆盖以下方法

    /**这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象
    *放在当前的ViewPager中
    **/
    instantiateItem(ViewGroup, int)
    /**这个方法,是从ViewGroup中移出当前View**/ 
    destroyItem(ViewGroup, int, Object)
    /**这个方法,是获取当前窗体界面数**/ 
    getCount()
    /**这个方法,在帮助文档中原文是could be implemented as return view == object,
    *也就是用于判断是否由对象生成界面
    **/
    isViewFromObject(View, Object)

    ViewPager onPageChangeListener                                        

    OnPageChangeListener这个接口需要实现三个方法:(onPageScrollStateChanged,onPageScrolled ,onPageSelected)

    onPageScrollStateChanged(int arg0)

    此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。

    arg0 ==1的时辰默示正在滑动,arg0==2的时辰默示滑动完毕了,arg0==0的时辰默示什么都没做。

    onPageScrolled(int arg0,float arg1,int arg2)

    当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为:

    arg0 :当前页面,及你点击滑动的页面

    arg1:当前页面偏移的百分比

    arg2:当前页面偏移的像素位置  

    onPageSelected(int arg0)

    此方法是页面跳转完后得到调用,arg0是你当前选中的页面的Position(位置编号)。

    我是天王盖地虎的分割线                                                                 

    1

    源代码:http://pan.baidu.com/s/1dD1Qx01

    viewpager学习.zip

    参考:http://www.cnblogs.com/tiantianbyconan/p/3364728.html

  • 相关阅读:
    C#入门分享(三)——C#常量与变量
    C#入门分享(二)——Visual Studio的应用与C#基本语法
    使用Axure设计基于中继器的左侧导航菜单
    关于C#调用非托管DLL,报“内存已损坏的”坑,坑,坑
    SQLserver 查询某个表的字段及字段属性
    关于数据库新建用户提示“用户、组或角色‘’XXX‘’在当前数据库中已已存在”的解决办法
    (转载)sqlserver2008”备份集中的数据库备份与现有的XX数据库不同”解决办法
    sql server 查询表字段的说明备注信息
    (转)软件产品化,对客户意味着什么?
    (转)软件产品化,国内IT人之痛
  • 原文地址:https://www.cnblogs.com/yydcdut/p/3889779.html
Copyright © 2011-2022 走看看