Fragment 可以兼容大小尺寸,例如:手机和平板,让布局能适应手机和平板,而不用维护两个,浪费资源和人力。
Fragment是一种可以嵌入在Activity当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛。
简单用法 左侧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 left_fragment.xml<LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="vertical" android:layout_width ="match_parent" android:layout_height ="match_parent" > <Button android:id ="@+id/button" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_gravity ="center_horizontal" android:text ="Button" /> </LinearLayout > class LeftFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.left_fragment, container, false) } }
右侧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 right_fragment.xml<LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="vertical" android:background ="#00ff00" android:layout_width ="match_parent" android:layout_height ="match_parent" > <TextView android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_gravity ="center_horizontal" android:textSize ="24sp" android:text ="This is right fragment" /> </LinearLayout > class RightFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.right_fragment, container, false) } }
activity_main.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="horizontal" android:layout_width ="match_parent" android:layout_height ="match_parent" > <fragment android:id ="@+id/leftFrag" android:name ="com.example.fragmenttest.LeftFragment" android:layout_width ="0dp" android:layout_height ="match_parent" android:layout_weight ="1" /> <fragment android:id ="@+id/rightFrag" android:name ="com.example.fragmenttest.RightFragment" android:layout_width ="0dp" android:layout_height ="match_parent" android:layout_weight ="1" /> </LinearLayout >
FragmentManager 使用 FragmentManager
来管理 Fragment
的添加、移除和替换操作。以下是如何使用 FragmentManager
替换一个 Fragment
的基本步骤:
1 2 3 4 5 val fragmentManager = supportFragmentManager val newFragment = NewFragment()val transaction = fragmentManager.beginTransaction() transaction.replace(R.id.fragmentContainer, newFragment) transaction.commit()
对于提交事务的方法,还有一个 commitAllowingStateLoss()
,它允许在一些特定情况下提交事务,即使可能存在状态丢失的风险。通常情况下,使用 commit()
来提交事务是更安全的方式,因为它会确保在状态变化(如设备旋转)时不会丢失事务的状态。
然而,有时候在异步操作或其他情况下,如果使用 commit()
来提交事务可能会导致 IllegalStateException
,此时可以考虑使用 commitAllowingStateLoss()
来避免崩溃,但要注意潜在的状态丢失问题。
Activity动态添加Fragment 另一个右侧,点击按钮动态变化右侧的fragment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 another_right_fragment.xml<LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="vertical" android:background ="#ffff00" android:layout_width ="match_parent" android:layout_height ="match_parent" > <TextView android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_gravity ="center_horizontal" android:textSize ="24sp" android:text ="This is another right fragment" /> </LinearLayout > class AnotherRightFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.another_right_fragment, container, false) } }
修改activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="horizontal" android:layout_width ="match_parent" android:layout_height ="match_parent" > <fragment android:id ="@+id/leftFrag" android:name ="com.example.fragmenttest.LeftFragment" android:layout_width ="0dp" android:layout_height ="match_parent" android:layout_weight ="1" /> <FrameLayout android:id ="@+id/rightLayout" android:layout_width ="0dp" android:layout_height ="match_parent" android:layout_weight ="1" > </FrameLayout > </LinearLayout >
将右侧Fragment替换成了一个FrameLayout。这是Android中最简单的一种布局,所有的控件默认都会摆放在布局的左上角。由于这里仅需要在布局里放入一个Fragment,不需要任何定位,因此非常适合使用FrameLayout。
MainActivity点击按钮动态添加另一个右侧fragment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class MainActivity : AppCompatActivity () { override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) button.setOnClickListener { replaceFragment(AnotherRightFragment()) } replaceFragment(RightFragment()) } private fun replaceFragment (fragment: Fragment ) { val fragmentManager = supportFragmentManager val transaction = fragmentManager.beginTransaction() transaction.replace(R.id.rightLayout, fragment) transaction.commit() } }
动态添加Fragment主要分为5步:
(1) 创建待添加Fragment的实例。
(2) 获取FragmentManager,在Activity中可以直接调用getSupportFragmentManager()方法获取。
(3) 开启一个事务,通过调用beginTransaction()方法开启。
(4) 向容器内添加或替换Fragment,一般使用replace()方法实现,需要传入容器的id和待添加的Fragment实例。
(5) 提交事务,调用commit()方法来完成。
Fragment中实现返回栈 通过点击按钮添加了一个Fragment之后,这时按下Back键程序就会直接退出。如果我们想实现类似于返回栈的效果,按下Back键可以回到上一个Fragment,该如何实现呢?
FragmentTransaction中提供了一个addToBackStack()方法,可以用于将一个事务添加到返回栈中。修改MainActivity中的代码,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 class MainActivity : AppCompatActivity () { ... private fun replaceFragment (fragment: Fragment ) { val fragmentManager = supportFragmentManager val transaction = fragmentManager.beginTransaction() transaction.replace(R.id.rightLayout, fragment) transaction.addToBackStack(null ) transaction.commit() } }
现在重新运行程序,并点击按钮将AnotherRightFragment添加到Activity中,然后按下Back键,你会发现程序并没有退出,而是回到了RightFragment界面。继续按下Back键,RightFragment界面也会消失,再次按下Back键,程序才会退出。
Fragment和Activity交互 如果想要在Activity中调用Fragment里的方法,或者在Fragment中调用Activity里的方法,应该如何实现呢?
Activity中调用Fragment中的方法:
1 2 3 4 val fragment = supportFragmentManager.findFragmentById(R.id.leftFrag) as LeftFragmentval fragment = leftFrag as LeftFragment
Fragment中调用Activity中的方法:
1 2 3 if (activity != null ) { val mainActivity = activity as MainActivity }
Activity和Fragment间数据传递 Activity向Fragment传递数据 使用Bundle
Bundle用来存储数据
setArguments()
方法将数据集绑定到Fragment中
**Activity
**:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); BlankFragment1 fragment = new BlankFragment1 (); Bundle bundle = new Bundle (); bundle.putString("name" ,"张三" ); fragment.setArguments(bundle); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(R.id.contain1,fragment); fragmentTransaction.commit(); } }
Fragment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class BlankFragment1 extends Fragment { @Override public void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); Bundle bundle = getArguments(); Log.d("ioc" , bundle.getString("name" )); } @Override public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_blank1, container, false ); } }
Fragment向Activity传递数据 方法1:使用Java接口
声明一个接口,使用接口实现Activity和Fragment之间的数据传输
接口的声明在Fragment中
接口的实现在Activity中
接口:
1 2 3 4 5 6 public interface IFragmentCallback { void sendMsgToActivity (String msg) ; String getMsgFromActivity () ; }
Fragment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class BlankFragment1 extends Fragment { private IFragmentCallback iFragmentCallback; public void setiFragmentCallback (IFragmentCallback iFragmentCallback ) { this .iFragmentCallback = iFragmentCallback; } @Override public void onCreate (@Nullable Bundle savedInstanceState ) { super .onCreate (savedInstanceState); iFragmentCallback.sendMsgToActivity ("你好,我来自Fragment" ); String msg = iFragmentCallback.getMsgFromActivity (); Log .d ("ioc" ,msg); } @Override public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { return inflater.inflate (R.layout .fragment_blank1 , container, false ); } }
Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); BlankFragment1 fragment = new BlankFragment1 (); IFragmentCallback iFragmentCallback = new IFragmentCallback () { @Override public void sendMsgToActivity (String msg) { Log.d("ioc" ,msg); } @Override public String getMsgFromActivity () { return "我来自Activity" ; } }; fragment.setiFragmentCallback(iFragmentCallback); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(R.id.contain1,fragment); fragmentTransaction.commit(); } }
Fragment之间互传数据 Fragment之间无法直接互传数据,需要一个Activity作为中间桥梁辅助两个Fragment之间数据传递
也就是Fragment向Activity传递数据,Activity又将数据传递给Fragment的组合。
例如点击某个列表项,跳转到对应的界面,并显示信息列表项的信息。
Fragment 1
1 2 3 4 5 6 7 8 9 10 11 12 13 iFragmentCallback iFragmentCallback; listview1.setOnItemClickListener(new AdapterView .OnItemClickListener() { @Override public void onItemClick (AdapterView<?> parent, View view, int position, long id) { TextView view1 = view.findViewById(R.id.text1); String name = view1.getText().toString(); Log.e("mylog" ,"fragment1发送数据:" +name+"给Activity" ); iFragmentCallback.sendMsgToActivity(name); } });
Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 iFragmentCallback iFragmentCallback = new iFragmentCallback () { @Override public void sendMsgToActivity (String msg) { Bundle bundle = new Bundle (); Log.e("mylog" ,"Activity得到fragment1传来的信息:" +msg); bundle.putString("name" ,msg); Fragment4 fragment4 = new Fragment4 (); Log.e("mylog" ,"Activity使用buddle将信息发送给fragment4" ); fragment4.setArguments(bundle); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.frame,fragment4); fragmentTransaction.commit(); } }; fragment1.iFragmentCallback = iFragmentCallback;
Fragment 2
1 2 3 4 5 6 7 8 9 public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_4, container, false ); TextView dialog = view.findViewById(R.id.thedialog); Bundle bundle = getArguments(); Log.e("mylog" ,"fragment4得到Activity发来的数据:" +bundle.getString("name" )); dialog.setText("与" +bundle.getString("name" )+"的会话窗口" ); return view; }
Fragment生命周期
onAttach()
:
当 Fragment
被附加到其 Activity
时调用。
可以使用 onAttach()
方法获取对宿主 Activity
的引用。
onCreate()
:
在 Fragment
被创建时调用。
可以进行初始化操作,但不能直接与用户界面交互。
onCreateView()
:
在 Fragment
创建视图时调用。
应该在这里创建 Fragment
的用户界面,并返回该界面的根视图。
onActivityCreated()
:
在与 Fragment
关联的 Activity
的 onCreate()
完成后调用。
可以在这里执行与 Activity
相关的操作。
onStart()
:
当 Fragment
可见时调用。
可以在这里执行与 UI 交互相关的操作。
onResume()
:
当 Fragment
处于活动状态时调用。
可以在这里开始耗时操作或者监听用户输入。
onPause()
:
当 Fragment
即将失去焦点或者被替换时调用。
应该停止与用户界面交互的操作。
onStop()
:
当 Fragment
不再可见时调用。
应该停止与 Activity
的交互。
onDestroyView()
:
在 Fragment
的视图被销毁时调用。
在这里进行释放资源的操作。
onDestroy()
:
在 Fragment
被销毁时调用。
在这里进行清理工作。
onDetach()
:
当 Fragment
与其宿主 Activity
分离时调用。
可以在这里释放对宿主 Activity
的引用。