以编程方式将 Fragment 添加到 Kotlin 中的 Activity

Posted

技术标签:

【中文标题】以编程方式将 Fragment 添加到 Kotlin 中的 Activity【英文标题】:Programmatically add Fragment to an Activity in Kotlin 【发布时间】:2020-05-09 13:57:56 【问题描述】:

我已经构建了一个片段,我希望将其放置在一个活动上。

到目前为止,我的代码如下所示:

MainActivity.kt

class MainActivity: AppCompatActivity() 

    @Inject
    lateinit var teamInfoModule: TeamInfoModule;

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        DaggerServiceModuleComponent.create().inject(this)

        val bundle = Bundle()
        val teamArrayList: ArrayList<Team> = this.teamInfoModule.getAllTeamData()
        val homeFragment = HomeFragment()

        bundle.putParcelableArrayList("teamData", teamArrayList)
        homeFragment.arguments = bundle

        val fragmentManager: FragmentManager = supportFragmentManager
        val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
        fragmentTransaction.replace(R.id.home_fragment, homeFragment).commit()
    

activity_main.xml

<layout 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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_
        android:layout_
        tools:context=".MainActivity"
        android:id="@+id/activity_main">
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

HomeFragment.kt

class HomeFragment @Inject constructor(): Fragment() 

    lateinit var team: Team

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        super.onCreateView(inflater, container, savedInstanceState)

        DaggerServiceModuleComponent.create().inject(this)

        val binding: ViewDataBinding = DataBindingUtil.inflate<ViewDataBinding>(inflater, R.layout.layout_home, container, false)
        print(arguments.toString())
        val allTeams: ArrayList<Team> = arguments?.get("teamData") as ArrayList<Team>

        this.team = allTeams[0]

        binding.setVariable(BR.team, team)

        return binding.root
    

layout_home.xml(绑定到 HomeFragment)

<?xml version="1.0" encoding="utf-8"?>

<layout 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">

    <data>
        <variable
            name="team"
            type="com.example.bluelightlite.models.Team" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_
        android:layout_
        tools:context=".fragments.HomeFragment">

        <androidx.cardview.widget.CardView
            android:layout_
            android:layout_
            android:layout_marginStart="1dp"
            android:layout_marginTop="79dp"
            android:layout_marginEnd="1dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <TextView
                android:id="@+id/info_text"
                android:layout_
                android:layout_
                android:text="@team.name"/>
        </androidx.cardview.widget.CardView>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

当它运行时,我得到错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.bluelightlite, PID: 10421
    java.lang.IllegalArgumentException: No view found for id 0x7f07003a (com.example.bluelightlite:id/activity_main) for fragment HomeFragment4b02ab3 (55c458bd-2931-48c6-8087-5e82641313c1) id=0x7f07003a

【问题讨论】:

【参考方案1】:

将片段添加到 Activity

private fun addFragmentToActivity(fragment: Fragment?)

    if (fragment == null) return
    val fm = supportFragmentManager
    val tr = fm.beginTransaction()
    tr.add(R.id.framlayout, fragment)
    tr.commitAllowingStateLoss()
    curFragment = fragment

在片段中添加片段

private fun addFragmentToFragment(fragment: Fragment)

 val ft = childFragmentManager.beginTransaction()
    ft.add(R.id.framlayout, fragment, fragment.javaClass.name)
    ft.commitAllowingStateLoss()

【讨论】:

尽量不要保留curFragment,除非您还通过当前已知的活动findFragmentByTagonCreate 中初始化它。【参考方案2】:

异常表示您正在尝试添加要与不存在的视图关联的片段。其实我也不确定R.id.home_fragment是从哪里来的。

解决办法是这样的:

<FrameLayout
    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_
    android:layout_
    tools:context=".MainActivity"
    android:id="@+id/root_container">
</FrameLayout>

然后

if(savedInstanceState == null)  // initial transaction should be wrapped like this
    supportFragmentManager.beginTransaction()
           .replace(R.id.root_container, homeFragment)
           .commitAllowingStateLoss()

所以说使用containerR.id.container 的另一个答案也是正确的,但是您也缺少setContentView(R.layout.activity_main)

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

【讨论】:

完美!!!非常感谢,我认为这里每个人的回答都是正确的,但没有人提到 setContentView... 设置为接受的答案 可以用androidx.fragment.app.FragmentContainerView代替FrameLayout吗? 当然,如果你愿意【参考方案3】:

用这样的容器 id 替换这一行

fragmentTransaction.replace(R.id.container, homeFragment).commit()

并在您的 mainactivity xml 中添加框架布局

<FrameLayout
    android:layout_
    android:layout_
    android:id="@+id/container"
    />

【讨论】:

嘿,我已经按照你说的做了,但现在我得到了同样的错误```No view found for id 0x7f070049 (com.example.bluelightlite:id/container) for fragment HomeFragment4b02ab3 (6dc9e25c-d62f-4ef7-a264-2ef39a773b5a) id=0x7f070049 ```【参考方案4】:

你需要给你的片段一个 id 并在活动布局中引用它。例如:


<fragment   android:name=com.example.bluelightlite.models.Team"
            android:id="@+id/Team"
            android:layout_weight="1"
            android:layout_
            android:layout_ />

【讨论】:

以上是关于以编程方式将 Fragment 添加到 Kotlin 中的 Activity的主要内容,如果未能解决你的问题,请参考以下文章

如何接收 GPS 位置并膨胀 Fragment MapView 以使用 SyncAdapter 以编程方式添加标记

以编程方式替换片段

显示/隐藏片段并以编程方式更改可见性属性

Android:编辑以编程方式添加的视图

以编程方式将 UISearchBar 添加到普通 ViewController 中以编程方式添加的 UITableView

以编程方式将按钮添加到导航栏