什么是Fragment
Fragment更像是Activity的简化版,而且他必需是Activity的一部分。可以组合多个Fragment放在一个Activity中,也可以多个Activity共用一个Fragment.
Fragment是Activity的一个模块化,他有自己的生命周期,接受自己的输入事件,可以在Activity运行时期(onResume)添加或删除。所以我们可以把之前写在Activity中的UI拆分到Fragment中,使UI代码模块话。
Fragment也解决了不同分辨率的UI显示问题
生命周期
Fragment有一套自己的生命周期
![]()
当一个fragment被创建的时候,它会经历以下状态。
onAttach() 和Activity进行关联,此时可以获得Acitivity
onCreate() 系统创建Fragments 时调用,可做执行初始化工作或者当程序被暂停或停止时用来恢复状态,跟Activity 中的onCreate相当。
onCreateView() 用于首次绘制用户界面的回调方法,必须返回要创建的Fragments 视图View。假如你不希望提供Fragments 用户界面则可以返回NULL。
onActivityCreated()
当这个fragment对用户可见的时候,它会经历以下状态。
onStart()
onResume() 在运行的activity中,并且可见。
当这个fragment进入“后台模式”的时候,它会经历以下状态。
onPause() 用户离开这个Fragments 的时候或fragment所在的activity被不完全覆盖,这时你要提交任何应该持久的变化.
onStop() 可能是它所在的activity处于stoped状态或是fragment被删除并添加到后退栈中了。此状态的fragment仍然存在于内中。
当这个fragment被销毁了(或者持有它的activity被销毁了),它会经历以下状态。
onPause()
onStop()
onDestroyView() 当fragment中的视图被移除的时候,调用这个方法。
onDetach() 当fragment和activity分离的时候,(fragment被从activity中删掉时)用调用这个方法。。
这里需要注意
只有当Activity进入onResumed状态后,Fragment才可以独立执行生命周期。除此之外Fragment会随着Activity的生命周期的改变而改变,比如Acitivity进入onPause,那么Fragment也会onPause.
并且当切换到另一个fragment的时候,会调用onPause-->onStop-->onDestroyView 切换回来时,onCreateView-->onActivityCreated-->onStart-->onResume 也就是说onAttach 和onCreate只调用了一次。
保存状态
Fragment也可以通过Bunlde来保存状态,当调用Activity的onSaveInstanceState()时,会调用Fragments.saveAllState()函数,把fragment状态的加到Activity的Bundle中,在下次onCreate()时Fragments.restoreAllState()。
Fragment使用
继承Fragment
public class MyFragment extends Fragment { public static final String ARG_ITEM_ID = "item_id"; public MyFragment(bundle arguments) { setArguments(arguments); //放入参数 } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle bundle=getArguments(); //取出参数 } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_item_detail, container, false); if (mItem != null) { ((TextView) rootView.findViewById(R.id.item_detail)).setText(mItem.content); } return rootView; } }
传入 onCreateView() 的 container 参数是你的fragment layout将被插入的父ViewGroup(来自activity的layout)。savedInstanceState 是一个 Bundle, 如果fragment是被恢复的,它提供关于fragment的之前的实例的数据。 (传入container是很重要的, 目的是为了让系统接受所要加载的layout的根view的layout参数)
inflate() 方法有3个参数:
- 1.想要加载的layout的resource ID.
- 2.加载的layout的父ViewGroup.
- 3.布尔值指示在加载期间, 展开的layout是否应当附着到ViewGroup (第二个参数).
- (在这个例子中, 指定了false, 因为系统已经把展开的layout插入到container – 传入true会在最后的layout中创建一个多余的view group.)
加载Fragment有两种方式
1.直接加入到XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <fragment class="com.xuzhi.MyFragment " android:id="@+id/titles" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" /> </LinearLayout>
当系统创建这个activity layout时, 它实例化每一个在layout中指定的fragment,并调用每一个上的onCreateView()方法。
注意: 每一个fragment都需要一个唯一的标识, 如果activity重启,系统可以用来恢复fragment(并且你也可以用来捕获fragment来处理事务,例如移除它.)
有3种方法来为一个fragment提供一个标识:
.为 android:id 属性提供一个唯一ID.
.为 android:tag 属性提供一个唯一字符串.
.如果以上2个你都没有提供, 系统使用容器view的ID.
2.通过FragmentTransaction.add进Activity的GroupView中
FragmentManager fragmentManager = getFragmentManager();//获得Manager FragmentTransaction ft = fragmentManager.beginTransaction();//获得Transaction,fragment的add,replace都是Transcation来控制 MyFragment fragment = new MyFragment(); ft.add(R.id.fragment_container, fragment);//第一个参数为容器的ID ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);//设置切换动画 ft.addToBackStack(null); ft.commit();//执行事务处理
一旦用FragmentTransaction做了改变,为了使改变生效,必须调用commit().
添加一个无UI的fragment
可以添加没有View的Fragment,使用重载方法add(Fragment,Tag String) 来添加 fragment (为fragment提供一个唯一的字符串"tag", 而不是一个view ID).但因为它没有关联到一个activity layout中的一个view, 所以不会接收到onCreateView()调用. 因此不必实现此方法.
Tag并不是专门针对无UI的fragment的 – 也可以提供字符串tag给有UI的fragment – 但是如果fragment没有UI,那么这个tag是仅有的标识它的途径. 如果随后你想从activity获取这个fragment, 需要使用 findFragmentByTag()。
FragmentManager管理Fragment
.使用findFragmentById() (用于在activity layout中提供一个UI的fragment)或findFragmentByTag() (适用于有或没有UI的fragment)获取activity中存在的fragment
.将fragment从后台堆栈中弹出, 使用 popBackStack() (模拟用户按下BACK 命令).
.使用addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener.
处理Fragment事务
我们可以对fragment进行add(),remove(),replace(),以及执行其他动作.提交给Activity的每一套变化被称为一个事务, 可以使用在 FragmentTransaction 中的 API 处理.而且可以保存每一个事务到一个Activity管理的back stack,允许用户经由fragment的变化往回导航(类似于通过activity往后导航).
注意,这里保存到BackStack中的是操作过程,而不是Fragment对象。
添加变化到 FragmentTransaction的顺序不重要, 除以下例外:
.必须最后调用 commit().
.如果添加多个fragment到同一个容器, 那么添加的顺序决定了它们在view hierarchy中显示的顺序.
.当执行一个移除fragment的事务时, 如果没有调用 addToBackStack(), 那么当事务提交后, 那个fragment会被销毁. 有鉴于此, 如果调用了 addToBackStack(), 那么 fragment会被onStop(), 如果用户导航回来,它将会被恢复.
commit()
调用 commit() 并不立即执行.它将事务安排排期, 一旦准备好, 就在activity的UI线程上运行(主线程). 也可以从UI线程直接调用executePendingTransactions() 来立即执行由commit()提交的事务. 但这么做通常不必要,。
注意:只能在activity保存它的状态(当用户离开activity)之前使用commit().
与Activity通信
获得对象
一个给定的Fragment之对应他绑定的Acitivty,Fragment可以使用 getActivity() 访问Activity实例, 并且容易地执行比如在activity layout中查找一个view的任务.
View listView = getActivity().findViewById(R.id.list);
Activity也可以通过从FragmentManager获得一个到Fragment的引用来调用fragment中的方法, 使用 findFragmentById() 或 findFragmentByTag().ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
为Activity创建事件回调方法
在这个例子中, OnArticleSelectedListener 接口在fragment A中声明:public static class MyFragment extends Fragment { OnArticleSelectedListener mListener = null; // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); } } }
如果activity没有实现接口, fragment会抛出 ClassCastException 异常.
添加项目到Action Bar
Fragment可以通过实现 onCreateOptionMenu() 提供菜单项给activity的选项菜单(以此类推, Action Bar也一样).为了使这个方法接收调用,无论如何, 你必须在 onCreate() 期间调用 setHasOptionsMenu() 来指出fragment愿意添加item到选项菜单(否则, fragment将接收不到对 onCreateOptionsMenu()的调用)随后从fragment添加到Option菜单的任何项,都会被追加到现有菜单项的后面.当一个菜单项被选择, fragment也会接收到 对 onOptionsItemSelected() 的回调.也可以在你的fragment layout中通过调用 registerForContextMenu() 注册一个view来提供一个环境菜单.当用户打开环境菜单, fragment接收到一个对 onCreateContextMenu() 的调用.当用户选择一个项目, fragment接收到一个对onContextItemSelected() 的调用.注意: 尽管你的fragment会接收到它所添加的每一个菜单项被选择后的回调, 但实际上当用户选择一个菜单项时, activity会首先接收到对应的回调.如果activity的on-item-selected回调函数实现并没有处理被选中的项目, 然后事件才会被传递到fragment的回调.
Be Continue
public class MyFragment extends Fragment { ... @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_item_detail, container, false); return rootView; } }