public class FooFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 为fragment提供 XML 布局文件 return inflater.inflate(R.layout.fragment_foo, container, false); } }
在代码中实现 Fragment 通常有两种方法,分别为静态实现和动态实现。html
1. 在 XML 中肯定 Fragment 内容java
在 XML 经过 android:name
参数来肯定 fragment 要显示的内容,这种方法创建的 fragment 不能够在程序运行过程当中移除,示例代码以下:android
<fragment android:name="com.fragment.FooFragment" tools:layout="@layout/fragment_foo" android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="wrap_content" />
其中的 com.fragment.FooFragment
为名为 FooFragment 的 Fragment Activity。安全
2. 在程序运行时肯定 Fragment 内容
首先,在 xml 布局文件中应该放置 FragmentLayout 做为 fragment 的容器,代码以下:ide
<FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/fragment_container"> </FrameLayout>
在声明了 android:id
以后,在 Java 代码中就能够操做这个 Fragment 容器了。可使用add()
, replace()
, remove()
等方法,示例代码以下:布局
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.remove(R.id.fragment_container, new FooFragment()); fragmentTransaction.commit();
3. add() 方法和 replace() 方法说明add()
方法是在原有的基础上添加一个 fragment,实现叠加的效果。replace()
方法是将原先全部的 fragment 移除,而后添加一个 fragment。ui
不要每次都 new 一个 Fragment,而是用 hide()
和 show()
方法来实现切换。spa
在 onCreate()
中先 add()
两个 fragment。线程
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fragment_container, homeFragment); fragmentTransaction.add(R.id.fragment_container, meFragment); fragmentTransaction.commit();
以后须要切换时,用以下方法实现。code
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.hide(meFragment); fragmentTransaction.show(homeFragment); fragmentTransaction.commit();
1. 如何理解 addToBackStack() 方法
fragmentTransaction.replace(R.id.fragment_container, new BarFragment()); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit();
在代码中,咱们能够看到,addToBackStack()
方法做用的对象是一个 transaction。也就是说,在执行这个 transaction 时,系统会创建一个回退栈,其中记录的是进行 transaction 先后 fragment 的内容。当手机上的 back 键按下时,最后创建的回退栈先进行响应,使得当前 fragment 先 remove 进行 transaction 后 fragment 的内容,再 add 上进行 transaction 前 fragment 的内容。
来一个实例,假设当前 fragment 内容为 C,先进行了一次有 addToBackStack 的replace(container, A)
,再进行一次无 addToBackStack 的replace(container, B)
时,若是触发了 back 事件,那么以前创建的回退栈响应,使 fragment 先 remove 掉 A,事实上原本就已经没了有,而后 add 上原先状态的C。此时,B是不会被 remove 掉的。因此,最后 fragment 中的内容为 B 和 C 二者的叠加。
若是但愿清空 fragment 的回退栈,能够采用在 replace 前加上 popBackStack()
方法,第二个参数为POP_BACK_STACK_INCLUSIVE。示例代码以下:
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.fragment_container, new FooFragment()); fragmentTransaction.commit();
2. 关于 fragmentTransaction 的延迟问题
fragmentTransaction.commit()
并非当即执行的,也并不是进入UI线程队列中等待顺序执行,而是由系统自动调配,在 UI 线程空闲时执行。这样就会产生一个问题,若是我须要获取到 fragment 中对象的实例,这个时候findViewById()
方法会返回 null ,那么如何解决这个问题呢?
第一种方法是经过getSupportFragmentManager().executePendingTransactions()
来让 transaction 当即加入UI线程执行,而不是被调配在空闲时间执行。可是若是是在其余线程中获取view,这个方法依然行不通,由于有可能UI线程自己正在进行一个相对耗时的操做,而第二种方法则更为安全。
第二种方法是在 fragment activity 的onCreateView()
方法中获取对应的view,示例代码以下:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_bar, container, false); textView = (TextView)rootView.findViewById(R.id.textbar); return rootView; }
references: