5. Fragment
5. Fragment
1. Fragment 和 Fragment 的生命周期
1. Fragment
- Fragment 是一种可以嵌入在 Activity 当中的 UI 片段
- 应用
- 使用 RecyclerView 展示一组新闻标题,点开新闻标题后有新闻详情
- 在手机中,新闻标题列表放在一个 Activity 中,将新闻的详细内容放在另一个 Activity 中,即两个 Activity
- 在平板中,将新闻标题列表界面和新闻详细内容界面分别放在两个 Fragment 中, 然后在同一个 Activity 里引入这两个 Fragment
2. 生命周期
-
Fragment 生命周期与 Activity 几乎类似
- 相似点,与 Activity 关联的 Fragment,如果 Activity 处于某一状态,则该 Fragment 也处于该状态
- 运行状态
- 暂停状态
- 停止状态
- 销毁状态
- 区别
- 将 Fragment 从 Activity 中移除时
- 如果调用了 addToBackStack,则进入停止状态
- 如果没调用 addToBackStack,则进入销毁状态
- 即将 Fragment 添加进返回栈后再移除,处于运行但是不可见的状态(停止状态)
- 将 Fragment 从 Activity 中移除时
- 相似点,与 Activity 关联的 Fragment,如果 Activity 处于某一状态,则该 Fragment 也处于该状态
-
onAttach():当 Fragment 和 Activity 建立关联时调用。
-
onCreateView():为 Fragment 创建视图(加载布局)时调用。
-
onActivityCreated():确保与 Fragment 相关联的 Activity 已经创建完毕时调用。
-
onDestroyView():当与 Fragment 关联的视图被移除时调用。
-
onDetach():当 Fragment 和 Activity 解除关联时调用。
- 启动 Activity 和 Fragment
- onAttach()、 onCreate()、onCreateView()、onActivityCreated()、onStart() 和 onResume()
- 切换为另一个 Fragment (使用addToBackStack)
- onPause()、onStop() 和 onDestroyView()
- 返回之前的 Fragment
- onCreateView()、onActivityCreated()、onStart() 和 onResume()
- 退出程序
- onPause()、onStop()、onDestroyView()、onDestroy() 和 onDetach()
2. 动态加载布局
- 在不同文件夹下,建立相同的 layout 文件,就能自动选择对应的布局
- 限定符
- 【截图】
- 最小宽度限定符(smallest-width qualifier)
- layout-sw600sp
- 单位为 dp
- 宽度大于等于 600 dp 的设备加载 layout-sw600dp/xxx 的布局
- 小于的加载 layout/xxx 的布局
- layout-sw600sp
- 限定符
3. 代码
-
Fragment
- 可以直接存放 Fragment
-
FrameLayout
- 可以动态加载 Fragment
-
修改代码
-
MainActivity2
-
package com.example.helloworld import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.widget.ArrayAdapter import android.widget.Button import android.widget.ListView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar class MainActivity2 : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.second_layout) // toolbar 部分 val toolbar: Toolbar = findViewById(R.id.toolbar2) setSupportActionBar(toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) // 设置返回按钮 toolbar.setNavigationOnClickListener { finish() } // 设置结束 act2 ActivityCollector.addActivity(this) // 从前一个 Activity 接收数据 val extraData1 = intent.getStringExtra("param1") val extraData2 = intent.getStringExtra("param2") Log.d("Activity2", "param1 is $extraData1, param2 is $extraData2") // 返回数据(但是未实现) val button2: Button = findViewById(R.id.button2) // 通过 id 找到 view, 并指明类型为 button button2.setOnClickListener { val intent = Intent().apply { putExtra("data_return", "Hello Activity1") } setResult(RESULT_OK, intent) finish() } // 关闭所有 Activity val button3: Button = findViewById(R.id.button3) button3.setOnClickListener { ActivityCollector.finishAll() } val button4: Button = findViewById(R.id.button4) button4.setOnClickListener { startNewActivity(this, MainActivity3::class.java) } val button5: Button = findViewById(R.id.button5) button5.setOnClickListener { startNewActivity(this, MainActivity4::class.java) } val button7: Button = findViewById(R.id.button7) button7.setOnClickListener { startNewActivity(this, FragmentActivity::class.java) } } }
-
-
second_layout
-
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar2" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" /> <Button android:id="@+id/button2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Back" /> <Button android:id="@+id/button3" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Quit App" /> <Button android:id="@+id/button4" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Go third" /> <Button android:id="@+id/button5" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Go forth" /> <Button android:id="@+id/button7" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Go Fragment" /> </LinearLayout>
-
-
-
新增代码
-
FragmentActivity
-
package com.example.helloworld import android.os.Bundle import android.util.Log import android.widget.Button import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.fragment.app.Fragment import com.example.helloworld.AnotherRightFragment.Companion import com.example.helloworld.ui.theme.HelloWorldTheme class FragmentActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.fragment_layout) ActivityCollector.addActivity(this) val button6: Button = findViewById(R.id.button6) // button6 在 Fragmentlayout 里面的 Fragment 中,但是会报错 button6.setOnClickListener { replaceFragment(AnotherRightFragment()) } replaceFragment(RightFragment()) // 交互 val leftFragment = LeftFragment.newInstance("a","") leftFragment.fragmentLog() val leftFragment2 = supportFragmentManager.findFragmentById(R.id.leftFrag) as? LeftFragment leftFragment2?.fragmentLog() val anotherFragment = AnotherRightFragment.newInstance("a","") anotherFragment.fragmentLog() val rightFragment = supportFragmentManager.findFragmentById(R.id.rightLayout) as? RightFragment rightFragment?.fragmentLog() // 没有打印 } // 动态添加 Fragment private fun replaceFragment(fragment: Fragment) { val fragmentManager = supportFragmentManager val transaction = fragmentManager.beginTransaction() // 开启一个事务 transaction.replace(R.id.rightLayout, fragment) // 向对应 FrameLayout 添加 fragment 对象 transaction.addToBackStack(null) transaction.commit() // 提交事务 } fun fragmentLog() { Log.d("FragmentActivity", "call activity from fragment") } }
-
-
LeftFragment
-
package com.example.helloworld import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private const val ARG_PARAM1 = "param1" private const val ARG_PARAM2 = "param2" /** * A simple [Fragment] subclass. * Use the [LeftFragment.newInstance] factory method to * create an instance of this fragment. */ class LeftFragment : Fragment() { // TODO: Rename and change types of parameters private var param1: String? = null private var param2: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { param1 = it.getString(ARG_PARAM1) param2 = it.getString(ARG_PARAM2) } val fragActivity = activity as? FragmentActivity // fragment 调用 activity fragActivity?.fragmentLog() } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_left, container, false) } fun fragmentLog() { Log.d("LeftFragment", "call fragment from activity") } companion object { /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment LeftFragment. */ // TODO: Rename and change types and number of parameters @JvmStatic fun newInstance(param1: String, param2: String) = LeftFragment().apply { arguments = Bundle().apply { putString(ARG_PARAM1, param1) putString(ARG_PARAM2, param2) } } } }
-
-
RightFragment
-
package com.example.helloworld import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private const val ARG_PARAM1 = "param1" private const val ARG_PARAM2 = "param2" /** * A simple [Fragment] subclass. * Use the [RightFragment.newInstance] factory method to * create an instance of this fragment. */ class RightFragment : Fragment() { // TODO: Rename and change types of parameters private var param1: String? = null private var param2: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { param1 = it.getString(ARG_PARAM1) param2 = it.getString(ARG_PARAM2) } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_right, container, false) } fun fragmentLog() { Log.d("RightFragment", "call fragment from activity") } companion object { /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment RightFragment. */ // TODO: Rename and change types and number of parameters @JvmStatic fun newInstance(param1: String, param2: String) = RightFragment().apply { arguments = Bundle().apply { putString(ARG_PARAM1, param1) putString(ARG_PARAM2, param2) } } } }
-
-
AnotherRightFragment
-
package com.example.helloworld import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private const val ARG_PARAM1 = "param1" private const val ARG_PARAM2 = "param2" /** * A simple [Fragment] subclass. * Use the [AnotherRightFragment.newInstance] factory method to * create an instance of this fragment. */ class AnotherRightFragment : Fragment() { // TODO: Rename and change types of parameters private var param1: String? = null private var param2: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { param1 = it.getString(ARG_PARAM1) param2 = it.getString(ARG_PARAM2) } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_another_right, container, false) } fun fragmentLog() { Log.d("AnotherRightFragment", "call fragment from activity") } companion object { /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment AnotherRightFragment. */ // TODO: Rename and change types and number of parameters @JvmStatic fun newInstance(param1: String, param2: String) = AnotherRightFragment().apply { arguments = Bundle().apply { putString(ARG_PARAM1, param1) putString(ARG_PARAM2, param2) } } } }
-
-
fragment_layout
-
<?xml version="1.0" encoding="utf-8"?> <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.helloworld.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="3" > </FrameLayout> </LinearLayout>
-
-
fragment_left
-
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".LeftFragment"> <Button android:id="@+id/button6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="Button" /> </FrameLayout>
-
-
fragment_right
-
<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>
-
-
fragment_another_right
-
<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>
-
-

浙公网安备 33010602011771号