Fragment 和 ViewPager 基础

来源:互联网 发布:erp软件的前景 编辑:程序博客网 时间:2024/06/06 00:37

Fragment

Fragment 可以有自己独立的事件处理和生命周期 , fragment最初是为了大屏幕显示而设计, 有了fragment后手机和平板兼容就容易了, 比如平板上 Activity A 包含
FragmentA 和 FragmentB , 手机上就可以ActivityA 包含FragmentA ; ActivityB包含FragmentB ; 就不用重新在手机上大改布局文件, 只需要小改… fragment 可以包含到多个Activity中

使用fragment需要先定义一个类, 继承Fragment 并实现其onCreateView()方法 , Fragment第一次绘制其用户界面的时候,系统会调用该方法, 为了绘制fragment的UI该方法必须返回一个View, 如果不显示UI, 返回null即可

静态和动态加载

Fragment静态加载: 就是在layout的xml文件中有定义 标签

在Activity的layout文件中声明Fragment , fragment的name属性, 指定了layout实例化的Fragment类
必须有标示, id属性唯一id 或 tag属性唯一字符串

Fragment动态加载: Activity的layout布局文件中没有定义fragment控件, 而是在Activity中用代码加载

但无论是静态还是动态 , 都需要有自定义的fragment类和这个fragment对应的layout文件
并且这个fragment类里面需要重写onCreateView方法, 返回view , 一般是把layout转换为view返回

    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment1, container);        TextView tv = (TextView) view.findViewById(R.id.id_fragment1_tv);        tv.setText("fragment 1 text");        Button btn = (Button) view.findViewById(R.id.id_fragment1_btn);        btn.setText("btnOfFragment1");        return view;    }

有了fragment类后, 动态加载需要fragment事务来加载到Activity
对fragment进行添加移除替换和其他动作, 提交给Activity的每一套变化称为事务

另外, 动态加载fragment最终还是把fragment加载到某个指定ID的layout

            //动态加载fragment到ID为id_fram的LinearLayout中            Fragment fragment = new MyFragment2();            FragmentManager manager = getFragmentManager();            FragmentTransaction beginTransaction = manager.beginTransaction();//开启事务            beginTransaction.add(R.id.id_frame, fragment);  //把fragment加载到指定ID的layout中            beginTransaction.addToBackStack(null);//fragment添加到返回栈             beginTransaction.commit();

每个事务都是一套变化 , 包括add() remove() replace() 然后提交给Activity, 必须调用commit() 方法
如果允许用户通过按下back返回到前一个fragment状态, 调用commit之前可以加入addToBackStack()方法

Fragment和Activity通信

1 fragment可以调用getActivity方法获取它所在的Activity
2 Activity可以调用FragmentManager的findFragmentById() 或findFragmentByTag()方法获取Fragment

Activity –> Fragment :

在Activity中创建Bundle数据包, 并调用Fragment的setArguments(Bundle bundle) 方法

Fragment –> Activity :
需要在
Fragment中定义一个内部回调接口, 再让包含该Fragment的Activity实现该回调接口. 这样在Fragment类中可以调用该回调方法将数据传递给Activity

Activity 传值给 Fragment :

//Activity端            @Override            public void onClick(View v) {                String data = tv_data.getText().toString();                //Activity中准备bundle数据                MyFragment4 myFragment4 = new MyFragment4();                Bundle bundle = new Bundle();                bundle.putString("data", data);                //加载fragment前, 调用fragment对象的setArguments方法传递数据                myFragment4.setArguments(bundle);                                //和往常一样动态加载fragment到某个控件                FragmentManager manager = getFragmentManager();                FragmentTransaction beginTransaction = manager.beginTransaction();                beginTransaction.replace(R.id.id_activity4_layout,myFragment4);                beginTransaction.addToBackStack(null);                beginTransaction.commit();                Toast.makeText(Activity4.this, "Activity 发送数据给Fragment4:" + data, Toast.LENGTH_SHORT).show();            }        });

//Fragment类中onCreateView方法中获取数据

    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState) {        // inflater将布局文件转换为view         View view = inflater.inflate(R.layout.fragment4, container, false);        ...        ....        //获取Activity传递的数据;        Bundle bundle = getArguments();        String txt = bundle.get("data").toString() ;        Toast.makeText(getActivity(), "fragment 接收到数据:"+txt, Toast.LENGTH_SHORT).show();        return view;    }

Fragment传值给Activity

fragment中定义接口, 然后activity实现接口方法,
fragment中onAttach 重写的时候, 把activity转换为接口实现对象,
fragment中在合适的地方调用activity强转接口对象中的方法 , 并传值, 于是实现fragment传递数据给activity

Fragment 类中:

public class MyFragment4 extends Fragment {//定义接口    public interface MyListener {        public void thankyou (String str);    }  //定义接口对象   MyListener mListener;   ...//复写onAttach方法时将实现了接口方法的activity强转并赋值给接口对象   @Override   public void onAttach(Activity activity) {              mListener = (MyListener) activity;        super.onAttach(activity);    }//在需要调用接口方法, 传值的时候调用接口方法    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState) {        // TODO Auto-generated method stub        View view = inflater.inflate(R.layout.fragment4, container, false);        ...        Bundle bundle = getArguments();        String txt = bundle.get("data").toString() ;        Toast.makeText(getActivity(), "fragment 接收到数据:"+txt, Toast.LENGTH_SHORT).show();//比如收到数据后, 返回一条确认字符串        mListener.thankyou(code);        return view;    }

//Activity中:

public class Activity4 extends Activity implements MyListener{    ...    ...    ...    //通过实现接口方法, 让fragment调用接口方法来实现fragment向Activity传值    @Override    public void thankyou(String str) {        Toast.makeText(Activity4.this, "Activity 接收到数据" + str, Toast.LENGTH_SHORT).show();    }}

activity传值给静态加载的fragment

Activity 的layout文件中有fragment字段, 静态加载MyFragment这个类的话

Fragment类中:

我们在MyFragment类中, 对需要传值的字段设置好getter , setter

 public class MyFragment1 extends Fragment {         private String testField;    public String getTestField() {        return testField;    }    public void setTestField(String testField) {        this.testField = testField;    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment1, container);        TextView tv = (TextView) view.findViewById(R.id.id_fragment1_tv);        tv.setText("fragment 1 text 静态加载");        Button btn = (Button) view.findViewById(R.id.id_fragment1_btn);        btn.setText("btnOfFragment1");             btn.setOnClickListener(new OnClickListener() {                     @Override            public void onClick(View v) {                String data = getTestField();                Toast.makeText(getActivity(), "testField 现在的值为:" + data, Toast.LENGTH_SHORT).show();            }        });        return view;    }   }

Activity中:

        FragmentManager fragmentManager = getFragmentManager();        Fragment fragment = fragmentManager.findFragmentById(R.id.id_activity4_staticFrag);        MyFragment1 myfragment1 = (MyFragment1) fragment;        myfragment1.setTestField("测试传值给fragment");

Fragment类中 调用 getXxx() 方法即可得到Activity传递过来的数据


ViewPager

类: android.support.v4.view.ViewPager

加载显示的页卡, 页卡可以使view对象也可以使fragment对象

将layout布局文件转换为view对象的方法:
1 LayoutInflater
LayoutInflater lf = getLayoutInflater().from(this);
lf.inflate(resource,root);

2 View.inflate
View.inflate(context,resource,root);

配置Adapter
数据源可以使view也可以使fragment
1. PagerAdapter 数据源List
2. FragmentPagerAdapter 数据源 List
3. FragmentStatePagerAdapter 数据源 List

view 作为页卡 , 最简单的viewPager

    //main.xml    <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"        tools:context="${relativePackage}.${activityClass}" >        <android.support.v4.view.ViewPager            android:id="@+id/id_pager"            android:layout_width="wrap_content"            android:layout_height="wrap_content" >        </android.support.v4.view.ViewPager>    </RelativeLayout>

Activity

//MainActivity.java    public class MainActivity extends Activity {        private List <View>   viewList;        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.main);            viewList = new ArrayList<View>();            /***             - view 对象作为数据源             */            View view1 = View.inflate(this, R.layout.view1, null);            View view2 = View.inflate(this, R.layout.view2, null);            View view3 = View.inflate(this, R.layout.view3, null);            View view4 = View.inflate(this, R.layout.view4, null);            viewList.add(view1);            viewList.add(view2);            viewList.add(view3);            viewList.add(view4);            //创建pager对象            ViewPager pager = (ViewPager) findViewById(R.id.id_pager);            //加载适配器            MyPagerAdapter adapter = new MyPagerAdapter(viewList);            pager.setAdapter(adapter);        }    }

//MyPagerAdapter

    package com.example.imooc_viewpager;    import java.util.List;    import android.support.v4.view.PagerAdapter;    import android.view.View;    import android.view.ViewGroup;    public class MyPagerAdapter extends PagerAdapter {        List<View> mViewList ;        public MyPagerAdapter(List<View> viewList) {            mViewList = viewList;        }        /**         -  返回页卡数量         */        @Override        public int getCount() {            // TODO Auto-generated method stub            return mViewList.size();        }        /***         - 判断view 是否来自对象         */        @Override        public boolean isViewFromObject(View arg0, Object arg1) {            // TODO Auto-generated method stub            return arg0 == arg1;        }        /**         - 实例化一个页卡 , viewpager一般是前, 后, 当前页卡, 一共3个页卡为单位的去操作          */        @Override        public Object instantiateItem(ViewGroup container, int position) {    //      return super.instantiateItem(container, position);            container.addView(mViewList.get(position));            return mViewList.get(position);        }        /***         - 销毁一个页卡 , 需要从viewGroup中移除一个view         */        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            container.removeView(mViewList.get(position));        }    }

加入页卡标题

1 XML文件中 , 加入PagerTabStrip 控件

    <android.support.v4.view.ViewPager        android:id="@+id/id_pager"        android:layout_width="wrap_content"        android:layout_height="wrap_content" >        <android.support.v4.view.PagerTabStrip            android:id="@+id/id_pager_tabStrip"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="top" >    //设置tabStrip在顶端显示        </android.support.v4.view.PagerTabStrip>    </android.support.v4.view.ViewPager>

2 Activity中准备标题数据

        private List <String> titleList;        titleList = new ArrayList<String> ();        titleList.add("第一页");        titleList.add("第二页");        titleList.add("第三页");        titleList.add("第四页");

3 自定义的MyPagerAdapter 类中实现getPageTitle 方法

//构造函数中传递titleList    List<View> mViewList ;    List<String> mTitleList;    public MyPagerAdapter(List<View> viewList , List<String> titleList) {        mViewList = viewList;        mTitleList = titleList;    }......        /**     * 设置页卡标题     */    @Override    public CharSequence getPageTitle(int position) {        return mTitleList.get(position);    }

4 设置属性

        //为tabStrip 设置属性        tabStrip  =  (PagerTabStrip) findViewById(R.id.id_pager_tabStrip);        tabStrip.setBackgroundColor(Color.YELLOW); //背景色        tabStrip.setTextColor(Color.RED); //文字颜色        tabStrip.setDrawFullUnderline(false); //去掉长的下划线        tabStrip.setTabIndicatorColor(Color.GREEN); //设置当前单项粗点的线的颜色

类似PagerTabStrip的还有PagerTitleStrip

        <android.support.v4.view.PagerTitleStrip            android:id="@+id/id_pager_titleStrip"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="bottom" >        </android.support.v4.view.PagerTitleStrip>

使用Fragment作为Pager数据源

1 XML文件中 , 加入PagerTabStrip 控件

    <android.support.v4.view.ViewPager        android:id="@+id/id_pager"        android:layout_width="wrap_content"        android:layout_height="wrap_content" >        <android.support.v4.view.PagerTabStrip            android:id="@+id/id_pager_tabStrip"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="top" >    //设置tabStrip在顶端显示        </android.support.v4.view.PagerTabStrip>    </android.support.v4.view.ViewPager>

2 创建Fragment类 , 注意使用的包 android.support.v4.app.Fragment; 兼容3.0以下版本

public class Fragment1 extends Fragment {    @Override    @Nullable    public View onCreateView(LayoutInflater inflater,            @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        return inflater.inflate(R.layout.view1, container, false);    }}

定义4个这样的fragment分别加载4个不同的layout文件

3 自定义FragmentPagerAdapter类

import java.util.List;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;/*** * FragmentPagerAdapter 和 PagerAdapter加载的时候不同的是,  * FragmentPagerAdapter 会一次把所有的fragment都加载进来, 而不是三个三个地加载 * @author hendry-code * */public class MyFragmentPagerAdapter extends FragmentPagerAdapter {    private List<Fragment> mFragList;    private List<String> mTitleList;    public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragList,            List<String> titleList) {        super(fm);        mFragList = fragList;        mTitleList = titleList;    }    @Override    public Fragment getItem(int arg0) {        // TODO Auto-generated method stub        return mFragList.get(arg0);    }    @Override    public int getCount() {        // TODO Auto-generated method stub        return mFragList.size();    }    @Override    public CharSequence getPageTitle(int position) {        return mTitleList.get(position);    }}

4 修改Activity文件, 使用fragmentAdapter

        private List<Fragment> fragList;        ...        /**         * Fragment 作为数据源         */        fragList = new ArrayList<Fragment>();        fragList.add(new Fragment1());        fragList.add(new Fragment2());        fragList.add(new Fragment3());        fragList.add(new Fragment4());        titleList = new ArrayList<String> ();        titleList.add("第一页");        titleList.add("第二页");        titleList.add("第三页");        titleList.add("第四页");        //创建pager对象        pager = (ViewPager) findViewById(R.id.id_pager);                //为tabStrip 设置属性        tabStrip  =  (PagerTabStrip) findViewById(R.id.id_pager_tabStrip);        tabStrip.setBackgroundColor(Color.YELLOW);        tabStrip.setTextColor(Color.RED);        tabStrip.setDrawFullUnderline(false); //去掉长的下划线        tabStrip.setTabIndicatorColor(Color.GREEN); //设置当前单项粗点的线的颜色        MyFragmentPagerAdapter fragmentAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragList, titleList);        pager.setAdapter(fragmentAdapter);

由于使用Fragment 是v4兼容包的Fragment, 所以 , FragmentPagerAdapter 的构造函数中需要一个fragmentManager 不能通过 getFragmentManager()来获得, 我们需要getSupportFragmentManager() ; 为了使用这个兼容包, 我们还需要把Activity改为继承自FragmentActivity.

使用FragmentStatePagerAdapter

FragmentPagerAdapter 是一次性加载所有的页卡, 没有动态添加销毁的功能 , 验证方法 , 在第四个fragment 销毁的时候打印LOG, 然后测试切换, 发现LOG没有打印

public class Fragment4 extends Fragment {    @Override    @Nullable    public View onCreateView(LayoutInflater inflater,            @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        return inflater.inflate(R.layout.view4, container, false);    }    @Override    public void onDestroy() {        // TODO Auto-generated method stub        super.onDestroy();        Log.i("main","Fragment4 destoryed....");    }}

所以如果页卡很多的话FragmentPagerAdapter就不适合了, 我们需要另外一个有动态添加销毁功能的 FragmentStatePagerAdapter
把adapter的定义头部改一下, 并复写创建和销毁方法 , 但这两个方法不用去改什么, 原样就可以了

public class MyFragmentPagerAdapter2 extends FragmentStatePagerAdapter {    ...    ...    @Override    public Object instantiateItem(ViewGroup arg0, int arg1) {        // TODO Auto-generated method stub        return super.instantiateItem(arg0, arg1);    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        // TODO Auto-generated method stub        super.destroyItem(container, position, object);    }...}Activity文件中:        MyFragmentPagerAdapter2 fragmentAdapter2 = new MyFragmentPagerAdapter2(getSupportFragmentManager(), fragList, titleList);        pager.setAdapter(fragmentAdapter2);

然后再模拟器上测试, 就发现从第三页切换到第二页的时候, 第四页的销毁LOG就被打印出来了, 说明FragmentStatePagerAdapter适配器是会动态维护创建销毁的


ViewPager 监听器 OnPageChangeListener

1 类定义的头文件
public class MainActivity extends FragmentActivity implements OnPageChangeListener {

2 完成接口方法, 主要是onPageSelected

    @Override    public void onPageScrollStateChanged(int arg0) {        // TODO Auto-generated method stub    }    @Override    public void onPageScrolled(int arg0, float arg1, int arg2) {        // TODO Auto-generated method stub    }    @Override    public void onPageSelected(int arg0) {        // TODO Auto-generated method stub        Toast.makeText(this, "当前是第" + (arg0 + 1) + "页面",Toast.LENGTH_SHORT).show();    }

3 OnCreate方法中 绑定Listener , pager.setOnPageChangeListener(this);

因为Fragment有完整的生命周期, 更好控制, 一般使用fragment + viewPager组合比较多…..

0 0
原创粉丝点击