Fragment 和 ViewPager 基础

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值