Fragment总结

来源:互联网 发布:用手机怎么改淘宝好 编辑:程序博客网 时间:2024/06/01 08:18

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添加的FrameLayoutarg3:当传进去这个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
原创粉丝点击