Fragment总结

Fragment

如何使用Fragment?

注意,使用的V4包中的Fragment!在这里我们全部使用android-support-v4.jar包里Fragment,不用系统自带的Fragment;这两个基本一样,但V4包中的相对功能更强大一些。

至于MainActivity,由于我们使用的V4包,必须将MainActivity派生自FragmentActivity,否则根本无法启动程序!因为系统的Activity只能用来盛装系统自带的Fragment,而无法盛装V4包中的Fragment,因为系统的Activity根本无法识别V4包中的Fragment,因为这根本就不是一块的代码!如果不使用V4包,使用系统自带的Fragment则不必将MainActivity派生自FragmentActivity。

1.XML静态添加Fragment(不推荐,所以以下不做详细解析)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:baselineAligned="false" >  

    <fragment  
        android:id="@+id/fragment1"  
        android:name="com.harvic.com.harvicblog2.Fragment1"  
        android:layout_width="0dip"  
        android:layout_height="match_parent"  
        android:layout_weight="1" />  

    <fragment  
        android:id="@+id/fragment2"  
        android:name="com.harvic.com.harvicblog2.Fragment2"  
        android:layout_width="0dip"  
        android:layout_height="match_parent"  
        android:layout_weight="1" />  

    </LinearLayout>  
2.动态添加Fragment
  • 1.在Activity的XML布局里面添加一个FrameLayout来盛装要添加的Fragment

<FrameLayout  
    android:id="@+id/fragment_container"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"/> 
  • 2.定义你自己的Fragment布局fragment.xml,并创建你的 Fragment

public class Fragment extends Fragment {  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        return inflater.inflate(R.layout.fragment, container, false);  
    }  
}  
  • 3.在Activiy中动态添加Fragment主要分为4步:

    • 1.获取到FragmentManager,在V4包中通过getSupportFragmentManager,在系统中原生的Fragment是通过getFragmentManager获得的。
    • 2.开启一个事务,通过调用beginTransaction方法开启。
    • 3.向容器内加入Fragment,一般使用add或者replace方法实现,需要传入容器的id和Fragment的实例。
    • 4.提交事务,调用commit方法提交。

FragmentManager manager = getSupportFragmentManager();  
FragmentTransaction transaction = manager.beginTransaction();  
Fragment1 fragment1 = new Fragment1(); 
/* 
arg1:是要将fragment盛装的container,就是Activity中XML添加的FrameLayout
arg3:当传进去这个TAG,它就会跟这个fragment关联起来,当我们通过findFragmentByTag()时,根据这个TAG就能找到这个Fragment实例。进而对它进行操作
*/ 
transaction.add(R.id.fragment_container, fragment1); 
//在通过transaction对Fragment操作完以后,一定要记得调用transaction.commit(),这样才会将操作提交到系统中,这里的代码才会最终起作用。 
transaction.commit(); 

FragmentManager

要管理activity中的fragments,你就需要使用FragmentManager。通过getFragmentManager()或getSupportFragmentManager()获得 常用的方法有:

manager.findFragmentById(); //根据ID来找到对应的Fragment实例,主要用在静态添加fragment的布局中,因为静态添加的fragment才会有ID  
manager.findFragmentByTag();//根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG来找到fragment实例  
manager.getFragments();//获取所有被ADD进Activity中的Fragment  

FragmentTransaction

一般用来对当前的Fragment进行管理。 常用的针对Fragment的方法有:

  • add()、replace()、remove()方法,需要注意的是:系统BUG——add()和replace()千万不要共用!!!

    //将一个fragment实例添加到Activity的最上层 
    add(int containerViewId, Fragment fragment); 
    add(int containerViewId, Fragment fragment, String tag);   
    //将一个fragment实例从Activity的fragment队列中删除  
    remove(Fragment fragment);  
    //替换containerViewId中的fragment实例,注意,它首先把containerViewId中所有fragment删除,然后再add进去当前的fragment  
    replace(int containerViewId, Fragment fragment);  
    replace(int containerViewId, Fragment fragment, String tag);<span style="line-height: 22.4px;"> </span>

       

我们上面说过replace操作会把Container中的所有fragment全部删除,然后再将指定的fragment添加进去!但Android在实现时出现了BUG!在replace()时,并不能把以前所有Fragment清空,就因为这个系统工程产了BUG就会导致add()和Replace()不能共用!
  • hide()、show()使用方法示例

    public FragmentTransaction hide(Fragment fragment);//将指定的fragment隐藏不显示   
    public FragmentTransaction show(Fragment fragment);//将以前hide()过的fragment显示出来
    

    如果我们使用replace来切换页面,那么在每次切换的时候,Fragment都会重新实例化,重新加载一边数据,这样非常消耗性能和用户的数据流量。 这是因为replace操作,每次都会把Container中的现有的fragment实例清空,然后再把指定的fragment添加进去,就就造成了在切换到以前的fragment时,就会重新实例会fragment。 正确的切换方式是add(),切换时hide(),add()另一个Fragment;再次切换时,只需hide()当前,show()另一个。 这样就能做到多个Fragment切换不重新实例化:(基本算法如下)

    FragmentManager manager = getSupportFragmentManager(); 
    FragmentTransaction transaction = manager.beginTransaction();
    Fragment oneFragment = manager.findFragmentByTag("oneFragment");  
    Fragment twoFragment = manager.findFragmentByTag("twoFragment"); 
    switchContent(oneFragment,twoFragment);
    
    public void switchContent(Fragment oneFragment, Fragment twoFragment) {  
        if (!twoFragment.isAdded()) {    // 先判断是否被add过  
            transaction.hide(oneFragment).add(R.id.content_frame, twoFragment).commit(); // 隐藏当前的fragment,add下一个到Activity中  
        } else {  
            transaction.hide(oneFragment).show(twoFragment).commit(); // 隐藏当前的fragment,显示下一个  
        }  
    }  
    

    大家可能觉得这里有个问题,如果我们要show()的fragment不在最顶层怎么办?如果不在ADD队列的队首,那显然show()之后是不可见的;那岂不影响了APP逻辑。大家有这个想法是很棒的,但在APP中不存在这样的情况,因为我们的APP的fragment是一层层ADD进去的,而且我们的fragment实例都是唯一的,用TAG来标识,当退出的时候也是一层层剥离的,所以当用户的动作导致要添加某个fragment时,那说明这个fragment肯定是在栈顶的。

fragment回退栈

  • 1、FragmentTransaction事务回滚使用方法:

    • 上部分,我们讲了有关添加、删除Fragment的操作,想将上一次commit的操作返回时,要怎么做呢。这就需要FragmentTransaction的回滚功能了。 要使用回滚功能,只需要要使用下面两个代码:

      /添加进栈
      //在transaction.commit()之前,使用addToBackStack()将其添加到回退栈中。
      transaction.addToBackStack(String tag);  
      
      //回退
      //在需要回退时,使用popBackStack()将最上层的操作弹出回退栈。
      manager.popBackStack(); 

      这里的popBackStack()是弹出默认的最上层的栈顶内容。 当栈中有多层时,我们可以根据id或TAG标识来指定弹出到的操作所在层。函数如下:

      /* 
      参数int id是当提交变更时transaction.commit()的返回值。
      参数string name是transaction.addToBackStack(String tag)中的tag值;
      至于int flags有两个取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE;
      当取值0时,表示除了参数一指定这一层之上的所有层都退出栈,指定的这一层为栈顶层; 
      当取值POP_BACK_STACK_INCLUSIVE时,表示连着参数一指定的这一层一起退出栈;
      */ 
      void popBackStack(int id, int flags);  
      void popBackStack(String name, int flags); 

            
  • 2、Transaction事务回退的原则

    这里我们着重讲一下,回退是以commit()提交的一次事务为单位的,而不是以其中的add,replace等等操作为单位回退的,即,如果我们在一次提交是添加了fragment2,fragment3,fragment4,那么回退时,会依据添加时的顺序,将它们一个个删除,返回到没有添加fragment4,fragment3,fragment2的状态。
       

fragment值传递

  • fragment参数传递方法一

    • 1.在Activity中定义一个字段、然后添加set和get方法、代码如下、mTitle就是要传递的参数、如果是传递对象、可以把mTitle换成一个对象即可

      public class DemoActivity {
      
          private String mTitle;
      
          public String getmTitle() {
              return mTitle;
          }
      
          public void setmTitle(String title) {
              this.mTitle = title;
          }
      }

    • 2.Fragment调用方法、需要注意的是在设值的时候要进行强转一下

      ((DemoActivity)getActivity()).getmTitle();

fragment参数传递方法二

  • 1.在fragment1中操作以下代码:

    Fragment2 fragment = new Fragment2();  
    Bundle args = new Bundle();  
    args.putString("param", "把值从fragment1传递给fragment2");  
    fragment.setArguments(args);  
    FragmentTransaction transaction = getFragmentManager().beginTransaction();  
    transaction.add(R.id.main_layout, fragment2);  
    transaction.addToBackStack(null);  
    transaction.commit();  

  • 2.然后在Fragment2的OnCreateView的时候再从arguments中获取参数:

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        View view =  inflater.inflate(R.layout.fragment2, container, false);  
        if (getArguments() != null) {  
            String mParam1 = getArguments().getString("param");  
            TextView tv =  (TextView)view.findViewById(R.id.textview);  
            tv.setText(mParam1);  
        }  
        return view;  
    }  

  • 3.如果还从Fragment2向Fragment1回传参数,那就需要到接口回调了。

与activity通讯

Fragment可以调用getActivity()方法很容易的得到它所在的activity的对象,然后就可以查找activity中的控件们(findViewById())还有activity中的方法。例如:

ViewlistView =getActivity().findViewById(R.id.list);

同样地,activity可以通过从FragmentManager获得一个Fragment的引用来调用fragment中的方法, 使用findFragmentByTag()或者findFragmentById().

ExampleFragment fragment =(ExampleFragment)getFragmentManager().findFragmentById(R.id.example_fragment)

activity响应fragment的事件

有时,你可能需要fragment与activity共享事件。一个好办法是在fragment中定义一个回调接口,然后在activity中实现之。

例如, 新闻APP用,通常在activity中有2个fragment – 一个在左边用来显示文章列表(ListFramgent), 另一个在右边显示文章内容(Contentfragment) – 然后ListFramgent必须告诉activity何时一个list item被选中,然后它可以告诉Contentfragment去显示文章.

  • 1、ContentFragment设置textView函数:

    public class ContentFragment extends Fragment {  
        private TextView mTv;  
        …………  
        public void setText(String text) {  
            mTv.setText(text);  
        }  
    }  

  • 2、ListFramgent中的处理方式:

    • (1)、定义接口及变量

      由于是用回调,所以要先定义一个接口及对应的变量:

      private titleSelectInterface mSelectInterface;  
      
      public interface titleSelectInterface{  
          public void onTitleSelect(String title);  
      } 

    • (2)、接口变量赋值 接口是给activity用的,所以要在activity中给这里的接口变量赋值,可以有很多方法,当然可以选择写一个setXXX()函数来赋值,但如果用户忘了怎么办?所以我们要强制用户赋值。所以采用强转的方式,在fragment与activity相关联时,进行强转赋值:

      public void onAttach(Activity activity) {  
          super.onAttach(activity);  
      
          try {  
              mSelectInterface = (titleSelectInterface) activity;  
          } catch (Exception e) {  
              throw new ClassCastException(activity.toString() + "must implement OnArticleSelectedListener");  
          }  
      }  

      采用强转的方式的问题在于,如果用户的activity没有implements titleSelectInterface,就会抛出错误,所以在调试过程中就会发现。

    • (3)、调用接口变量 下一步就是在ListFramgent中在用户点击listView的item的时候,将结果回传给Activity了,代码如下:

      public void onActivityCreated(Bundle savedInstanceState) {  
          super.onActivityCreated(savedInstanceState);  
      
          listView = (ListView) getView().findViewById(R.id.list);//获取自己视图里的控件引用,方法二  
          ArrayAdapter arrayAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mStrings);  
          listView.setAdapter(arrayAdapter);  
          listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
              @Override  
              public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
                  String str = mStrings[position];  
                  mSelectInterface.onTitleSelect(str);  
              }  
          });  
      }  

    • (4)、在Activity中实现titleSelectInterface接口 首先是MainActivity必须实现titleSelectInterface接口,然后结果会在onTitleSelect(String title)中返回,在结果返回后利用ContentFragment.setText()操作textView;代码如下:

      public class MainActivity extends FragmentActivity implements Fragment1.titleSelectInterface {  
      
      ……  
      
      @Override  
      public void onTitleSelect(String title) {  
          FragmentManager manager = getSupportFragmentManager();  
          ContentFragment contentFragment = (ContentFragment)manager.findFragmentById(R.id.content_fragment);  
          contentFragment.setText(title);  
      }  
      }  

    在上面代码中可以看出,在结果返回后,通过findFragmentById()来获得ContentFragment的实例,这里首次出现了findFragmentById()函数的用法,这个函数主要用来静态添加的fragment中,通过fragment的ID值来获取它的实例。在获得ContentFragment的实例以后,通过调用我们写好了setText()方法来将结果显示在textView中。

    ContentFragment contentFragment = (ContentFragment)manager.findFragmentById(R.id.content_fragment);  



大部分内容摘自: http://blog.csdn.net/harvic880925/article/details/44927375  harvic博客















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值