一.创建Fragment
1.一般情况下,你至少需要实现以下几个生命周期方法:
onCreate()
- 在创建fragment时系统会调用此方法。在实现代码中,你可以初始化想要在fragment中保持的那些必要组件,当fragment处于暂停或者停止状态之后可重新启用它们。
onCreateView()
- 在第一次为fragment绘制用户界面时系统会调用此方法。为fragment绘制用户界面,这个函数必须要返回所绘出的fragment的根View。如果fragment没有用户界面可以返回空。
onPause()
- 系统回调用该函数作为用户离开fragment的第一个预兆(尽管这并不总意味着fragment被销毁)。在当前用户会话结束之前,通常要在这里提交任何应该持久化的变化(因为用户可能不再返回)。
inflate()函数需要以下三个参数:
(1)要inflate的布局的资源ID。
(2)被inflate的布局的父ViewGroup。传入container很重要,这是为了让系统将布局参数应用到被inflate的布局的根view中去,由其将要嵌入的父view指定。
(3)一个布尔值,表明在inflate期间被infalte的布局是否应该附上ViewGroup(第二个参数)。
3.将fragment添加到activity之中
(1)在activity的布局中声明fragment
<fragment>中的android:name 属性指定了布局中实例化的Fragment类
注意:每个fragment都需要一个唯一的标识,如果重启activity,系统可用来恢复fragment(并且可用来捕捉fragment的事务处理,例如移除)。为fragment提供ID有三种方法:
- 用android:id属性提供一个唯一的标识。
- 用android:tag属性提供一个唯一的字符串。
- 如果上述两个属性都没有,系统会使用其容器视图(view)的ID。
eg. FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
传入add()函数:第一个参数是fragment被放置的ViewGroup,它由资源ID(resource ID)指定,
第二个参数就是要添加的fragment
4.添加无界面的fragment
想要添加没有界面的fragment ,可以使用add(Fragment, String)(为fragment提供一个唯一的字符串“tag”,而不是视图(view)ID)。
为无界面fragment提供字符串标签并不是专门针对无界面fragment的——也可以为有界面fragment提供字符串标签——但是对于无界面fragment,字符串标签是唯一识别它的方法。如果之后想从activity中取到fragment,需要使用findFragmentByTag()。
二.管理Fragments
通过getFragmentManager()获得的FragmentManager 可以做如下事情,包括:
- 使用findFragmentById()(用于在activity布局中提供有界面的fragment)或者findFragmentByTag()获取activity中存在的fragment(用于有界面或者没有界面的fragment)。
- 使用popBackStack()(模仿用户的BACK命令)从后台栈弹出fragment。
- 使用addOnBackStackChangedListener()注册一个监听后台栈变化的监听器。
1.将变更添加到FragmentTransaction中的顺序注意以下两点:
(1)必须要在最后调用commit()
(2)如果你正将多个fragment添加到同一个容器中,那么添加顺序决定了它们在视图层次里显示的顺序。
2.在执行删除fragment事务时,没有调用addToBackStack(),那么事务一提交fragment就会被销毁,而且用户也无法回退它。然而,当移除一个fragment时,调用了addToBackStack(),那么之后fragment会被停止,如果用户回退,它将被恢复过来。
提示:对于每一个fragment事务,在提交之前通过调用setTransition()来应用一系列事务动作。
警告:只能在activity保存状态(当用户离开activity时)之前用commit()提交事务。如果你尝试在那时之后提交,会抛出一个异常。这是因为如果activity需要被恢复,提交后的状态会被丢失。对于这类丢失提交的情况,可使用commitAllowingStateLoss()
四.与activity交互
***fragment可以通过getActivity()函数访问Activity
eg.View listView = getActivity().findViewById(R.id.list);
***activity能够调用fragment的函数findFragmentById()或者findFragmentByTag() eg.ExampleFragment fragment = (ExampleFragment) getFragmentManager()
.findFragmentById(R.id.example_fragment);
1.创建activity事件回调函数
在一些情况下,你可能需要fragment与activity共享事件。这样做的一个好方法是在fragment内部定义一个回调接口,并需要宿主activity实现它。当activity通过接口接收到回调时,可以在必要时与布局中的其它fragment共享信息。为了确保宿主activity实现了这个接口,fragment的onAttach()回调函数(当添加fragment到activity中时系统会调用它)通过作为参数传入onAttach()的activity的类型转换来实例化一个在fragment里定义的接口(SampleListener)的实例。
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (SampleListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement SampleListener");
}
}
如果activity没有实现这个接口,那么fragment会抛出一个ClassCaseException异常。一旦成功,mListener成员会保留一个activity的SampleListener实现的引用,由此fragment可以通过调用由SampleListener接口定义的方法与activity共享事件。
2.添加items到ActionBar
你的fragments可以通过实现onCreateOptionsMenu()来构建菜单项到activity的Options Menu(因此Action Bar也一样)。为了使用这个方法接收到调用,不管怎样,你必须在onCreate()期间调用setHasOptionsMenu(),来指明想要添加项目到Options Menu的那个fragment(否则,fragment将接收不到onCreateOptionsMenu()的调用)。
任何想要在fragment中的Options Menu添加的项目都追加到已有的菜单项后面。当菜单项被选中时,fragment也会接收到对onOptionsItemSelected()的回调。
你也可以通过调用registerForContextMenu()在fragment布局中注册一个view以提供一个context menu。当用户打开context menu时,fragment接收到对onCreateContextMenu()的回调。当用户选中一个项目时,fragment接收到对onContextItemSelected()的回调。
注意:尽管你的fragment会接收到为添加到每个菜单项被选择菜单项的回调,但当用户选择一个菜单项时,activity会首先接收到对应的回调。如果activity的选择菜单项回调的实现没有处理被选中的项目,那么该事件被传递给fragment的回调。这同样适用于Options Menu和context menu。
五.处理Fragment的生命周期
同activity类似,你可以用Bundle保存fragment状态,万一activity的进程被杀掉了,并且在activity被重新创建时,你需要恢复fragment状态。在回调执行fragment的onSaveInstanceState()期间保存状态,在onCreate()或者onCreateView()或者onActvityCreate()中可以恢复状态。
1.与activity生命周期的协调合作
Fragment有一些额外的生命周期回调方法:
-
onAttach()
- 当fragment被绑定到activity时调用(Activity会被传入)。
-
onCreateView()
- 创建与fragment相关的视图体系时被调用。
-
onActivityCreated()
- 当activity的onCreate()函数返回时被调用。
-
onDestroyView()
- 当与fragment关联的视图体系正被移除时被调用。
-
onDetach()
- 当fragment正与activity解除关联时被调用。
一旦activity处于resumed状态,则可以在activity中自由的添加或者移除fragment。因此,只有当activity处于resumed状态时,fragment的生命周期才可以独立变化。
2.例子:
主Activity布局--纵向的
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fl_title"
android:name="com.example.administrator.fragmentlearn.TitleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></fragment>
</RelativeLayout>
主Activity布局--横向的
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="@+id/fl_title"
android:name="com.example.administrator.fragmentlearn.TitleFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></fragment>
<FrameLayout
android:id="@+id/fl_detail"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></FrameLayout>
</LinearLayout>
TitleFragment.java
public class TitleFragment extends ListFragment {// 因为继承的是ListFragment,
// 所以不用实现onCreateView()的方法,因为已经默认实现了
public static String POSITION = "position";
private String[] titles = {"标题一", "标题二", "标题三", "标题四", "标题五", "标题六"};
private int curPosition = 0;// 当前选择的是第几个标题
private boolean isPaint;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_activated_1, titles));
if (savedInstanceState != null)
curPosition = savedInstanceState.getInt(POSITION);
View view = getActivity().findViewById(R.id.fl_detail);
isPaint = view != null && view.getVisibility() == View.VISIBLE;
if (isPaint) {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetail();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(POSITION, curPosition);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
curPosition = position;
showDetail();
}
private void showDetail() {
if (isPaint) {
getListView().setItemChecked(curPosition, true);
DetailFragment fragment = (DetailFragment) getFragmentManager().findFragmentById(R.id.fl_detail);
if (fragment == null || fragment.getShownPosition() != curPosition) {
fragment = DetailFragment.newInstance(curPosition);
getFragmentManager().beginTransaction().replace(R.id.fl_detail, fragment).commit();
}
} else {
Intent intent = new Intent(getActivity(),DetailActivity.class);
intent.putExtra(POSITION,curPosition);
startActivity(intent);
}
}
}
DetailFragment.java
import static com.example.administrator.fragmentlearn.TitleFragment.POSITION;
public class DetailFragment extends Fragment {
public static DetailFragment newInstance(int position) {
DetailFragment fragment = new DetailFragment();
Bundle args = new Bundle();
args.putInt(POSITION, position);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null)// 防止不是横屏时调用此类
return null;
ScrollView scrollView = new ScrollView(getActivity());
TextView textView = new TextView(getActivity());
int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getActivity().getResources().getDisplayMetrics());
textView.setPadding(padding, padding, padding, padding);
String content = getShownPosition() + "开始";
for (int i = 0; i < 100; i++)
content += "标题" + getShownPosition() + "下的内容";
textView.setText(content);
scrollView.addView(textView);
return scrollView;
}
public int getShownPosition() {
return getArguments().getInt(POSITION);
}
}
DetailActivity.java
import static com.example.administrator.fragmentlearn.TitleFragment.POSITION;
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
finish();
return;// 防止横向时调用此类(竖屏进入到详情后,再横屏会发生)
}
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(android.R.id.content, DetailFragment.newInstance(getIntent().getIntExtra(POSITION, 0))).commit();
}
}
}