IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 二、Fragment相关生命周期、动态添加 -> 正文阅读

[移动开发]二、Fragment相关生命周期、动态添加

使用Fragment 我们可以把页面结构划分成几块,每块使用一个Fragment来管理。这样我们可以更加方便的在运行过程中动态地更新Activity中的用户界面,日后迭代更新、维护也是更加方便

注意事项: Fragment并不能单独使用,他需要嵌套在Activity 中使用,尽管他拥有自己的生命周期,但是还是会受到宿主Activity的生命周期的影响,比如Activity 被destory销毁了,他也会跟着销毁!一个Activity可以嵌套多个Fragment。

图片和部分文字转载自https://www.songyubao.com/book/primary/activity/fragment.html

fragment_xmind

1.Fragment的生命周期

fragment_lifecycle

四个场景用于加深对Fragment生命周期的理解

①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume

②当我们启动一个新的页面, 此时Fragment所在的Activity不可见,会执行 onPause

③当新页面返回后,当前Activity和Fragment又可见了,会再次执行onStartonResume

④退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop -> onDestoryView -> onDestory -> onDetach

onActivityCreated 已过时

常用 onCreateView 当前fragment所对应的视图对象

onResume 恢复动画/视频播放

2. Fragment的动态添加与数据传递

2.1 动态添加Fragment

class SecondActivity : AppCompatActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)


        val fragment  = SecondFragment()
        //事务操作对象
        val ft:FragmentTransaction = supportFragmentManager.beginTransaction()
        ft.add(R.id.container , fragment)
        ft.commitAllowingStateLoss()
    }
}

2.2 Fragment常见的操作

val fragment = StudyFragment()
val ft = supportFragmentManager.beginTransaction()

if(!fragment.isAdded()){
  ft.add(R.id.container,fragment) //把fragment添加到事务中,当且仅当该fragment未被添加过
}
ft.show(fragment) //显示出fragment的视图
ft.hide(fragment) //隐藏fragment,使得它的视图不可见
ft.remove(fragment)//移除fragment
//替换fragment,之前添加过的fragment都会被暂时移除,把当前这个fragment添加到事务中
ft.replace(R.id.container,fragment)

//提交事务,执行对fragment的add、replace、show、hide操作
ft.commitAllowingStateLoss() 

2.3 给Fragment传递数据

Activity传入数值

class SecondActivity : AppCompatActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        val fragment  = SecondFragment()

        //给Fragment传递数据
        val bundle = Bundle()
        bundle.putInt("int_extra" , 100)
        bundle.putString("string_extra" , "string_extra")
        fragment.arguments = bundle

        //事务操作对象
        val ft:FragmentTransaction = supportFragmentManager.beginTransaction()
        ft.add(R.id.container , fragment)
        ft.commitAllowingStateLoss()
    }
}

Fragment接受数据

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val intValue = arguments?.getInt("int_extra")
    val strValue = arguments?.getString("string_extra")
	
    //view是onCreateView return的view
    val textview = view as TextView
    textview.text = "${intValue} ---${strValue}"
}

思考:运行时Fragment如何获取Activity中的数据、又如何将数据传递到Activity中呢?

https://developer.android.com/guide/fragments/communicate?hl=zh-cn

设计并实现底部导航栏页面结构

Activity页面布局

此布局和如果 创建项目选择带导航栏 的样式相同

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout                  
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.google.android.material.button.MaterialButtonToggleGroup 
        android:id="@+id/toggle_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:selectionRequired="false"
        android:background="#08000000"
        app:singleSelection="true">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/tab1"
            style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:backgroundTint="@android:color/transparent"
            android:text="Tab1"
            android:textColor="#000000"
            android:textSize="12sp"
            app:icon="@drawable/ic_home_black_24dp"
            app:iconGravity="textTop"
            app:iconTint="@color/black"
            tools:ignore="HardcodedText" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/tab2"
            style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:backgroundTint="@android:color/transparent"
            android:text="Tab2"
            android:textColor="#000000"
            android:textSize="12sp"
            app:icon="@drawable/ic_notifications_black_24dp"
            app:iconGravity="textTop"
            app:iconTint="@color/black"
            tools:ignore="HardcodedText" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/tab3"
            style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:backgroundTint="@android:color/transparent"
            android:text="Tab3"
            android:textColor="#000000"
            android:textSize="12sp"
            app:icon="@drawable/ic_dashboard_black_24dp"
            app:iconGravity="textTop"
            app:iconTint="@color/black"
            tools:ignore="HardcodedText" />

    </com.google.android.material.button.MaterialButtonToggleGroup>
</LinearLayout>

tips

1.占用父布局(除了导航栏)剩余的空间

 android:layout_height="0dp"
 android:layout_weight="1"

2.水平平分

android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"

监听选中事件

onCreate方法中

//改变选中按钮的颜色
binding.toggleGroup.addOnButtonCheckedListener { group:MaterialButtonToggleGroup, checkedId:Int , isChecked:Boolean ->
    val childCount = group.childCount
    var selectIndex = 0
    for (index in 0 until childCount){
        val button = group.getChildAt(index) as MaterialButton
        if(button.id == checkedId){
            //选中的按钮变红
            selectIndex = index
            button.setTextColor(Color.CYAN)
            button.iconTint = ColorStateList.valueOf(Color.CYAN)
        } else {
            button.setTextColor(Color.BLACK)
            button.iconTint = ColorStateList.valueOf(Color.BLACK)
        }
    }
    switchFragment(selectIndex)
}
binding.toggleGroup.check(binding.tab1.id)

导航栏切换动态切换显示的fragment

private var tab1Fragment:SecondFragment?=null
private var tab2Fragment:SecondFragment?=null
private var tab3Fragment:SecondFragment?=null
private var shownFragment:Fragment ?= null //当前正在显示的Fragment

//切换Fragment
private fun switchFragment(selectIndex: Int) {
    //根据选中tab的id返回fragment
     val fragment = when(selectIndex){
        0->{
            if(tab1Fragment == null){
                tab1Fragment = SecondFragment()
                val bundle = Bundle()
                bundle.putString("tab" , "tab1")
                tab1Fragment!!.arguments = bundle
            }
            tab1Fragment
        }1->{
            if(tab2Fragment == null){
                tab2Fragment = SecondFragment()
                val bundle = Bundle()
                bundle.putString("tab" , "tab2")
                tab2Fragment!!.arguments = bundle
            }
            tab2Fragment
        }2->{
            if(tab3Fragment == null){
                tab3Fragment = SecondFragment()
                val bundle = Bundle()
                bundle.putString("tab" , "tab3")
                tab3Fragment!!.arguments = bundle
            }
            tab3Fragment
        }else -> {
            throw IllegalStateException("下标不符合预期")
        }
     }?:return


    val ft = supportFragmentManager.beginTransaction()
    if(!fragment.isAdded){
        ft.add(R.id.container , fragment)
    }
    ft.show(fragment)
    //避免出现多个fragment重叠
    if(shownFragment !=null){
        ft.hide(shownFragment!!)
    }
    shownFragment = fragment
    ft.commitAllowingStateLoss()
}

本例中多个fragment的生命周期

第一次点击各个tab 每个fragment onAttach----> onResume

2021-11-11 16:34:22.661 5666-5666/com.example.componentlearn E/SecondFragment: onAttach
2021-11-11 16:34:22.662 5666-5666/com.example.componentlearn E/SecondFragment: onCreate
2021-11-11 16:34:22.665 5666-5666/com.example.componentlearn E/SecondFragment: onCreateView
2021-11-11 16:34:22.675 5666-5666/com.example.componentlearn E/SecondFragment: onStart
2021-11-11 16:34:22.679 5666-5666/com.example.componentlearn E/SecondFragment: onResume
2021-11-11 16:34:24.570 5666-5666/com.example.componentlearn E/SecondFragment: onHiddenChanged : tab1-- true
2021-11-11 16:34:24.573 5666-5666/com.example.componentlearn E/SecondFragment: onAttach
2021-11-11 16:34:24.574 5666-5666/com.example.componentlearn E/SecondFragment: onCreate
2021-11-11 16:34:24.575 5666-5666/com.example.componentlearn E/SecondFragment: onCreateView
2021-11-11 16:34:24.576 5666-5666/com.example.componentlearn E/SecondFragment: onStart
2021-11-11 16:34:24.577 5666-5666/com.example.componentlearn E/SecondFragment: onResume
2021-11-11 16:34:25.737 5666-5666/com.example.componentlearn E/SecondFragment: onHiddenChanged : tab2-- true
2021-11-11 16:34:25.739 5666-5666/com.example.componentlearn E/SecondFragment: onAttach
2021-11-11 16:34:25.740 5666-5666/com.example.componentlearn E/SecondFragment: onCreate
2021-11-11 16:34:25.741 5666-5666/com.example.componentlearn E/SecondFragment: onCreateView
2021-11-11 16:34:25.741 5666-5666/com.example.componentlearn E/SecondFragment: onStart
2021-11-11 16:34:25.745 5666-5666/com.example.componentlearn E/SecondFragment: onResume

tab3切换tab2

2021-11-11 16:35:53.583 5666-5666/com.example.componentlearn E/SecondFragment: onHiddenChanged : tab3-- true
2021-11-11 16:35:53.584 5666-5666/com.example.componentlearn E/SecondFragment: onHiddenChanged : tab2-- false

tab2切换tab1

2021-11-11 16:35:55.533 5666-5666/com.example.componentlearn E/SecondFragment: onHiddenChanged : tab2-- true
2021-11-11 16:35:55.533 5666-5666/com.example.componentlearn E/SecondFragment: onHiddenChanged : tab1-- false

当且仅当activity存在多个fragment , 并且我们调用了show - hide

fragment的生命周期会调用

override fun onHiddenChanged(hidden: Boolean)

不可见为true , 可见为false

Bug记录

使用view-binding的时候 addOnButtonCheckedListener无效果

原因setContentView位置和内容写错

正确的是

private lateinit var binding: ActivitySecondBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivitySecondBinding.inflate(layoutInflater)
    setContentView(binding.root)
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-12 19:42:39  更:2021-11-12 19:43:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:17:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码