以编程方式将片段添加到Kotlin中的活动

时间:2020-01-23 10:16:56

标签: android xml android-fragments kotlin

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

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

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_width="match_parent"
        android:layout_height="match_parent"
        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_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".fragments.HomeFragment">

        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            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_width="match_parent"
                android:layout_height="match_parent"
                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 HomeFragment{4b02ab3 (55c458bd-2931-48c6-8087-5e82641313c1) id=0x7f07003a}

4 个答案:

答案 0 :(得分:2)

该异常表明您正在尝试添加要与不存在的视图关联的Fragment。实际上,我不确定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_width="match_parent"
    android:layout_height="match_parent"
    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)

答案 1 :(得分:1)

将片段添加到活动

private fun addFragmentToFragment(fragment: Fragment){

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

在片段中添加片段

var exportSession: AVAssetExportSession!


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            picker.dismiss(animated: true, completion: nil)

        guard let videoURL = (info[UIImagePickerController.InfoKey.mediaURL] as? URL) else { return }
        encodeVideo(videoURL)
    }

func encodeVideo(_ videoURL: URL)  {
        let avAsset = AVURLAsset(url: videoURL, options: nil)

        //Create Export session
        exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough)

        let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
        let filePath = documentsDirectory.appendingPathComponent("rendered-Video.mp4")
        deleteFile(filePath)

        exportSession!.outputURL = filePath
        exportSession!.outputFileType = AVFileType.mp4
        exportSession!.shouldOptimizeForNetworkUse = true
        let start = CMTimeMakeWithSeconds(0.0, preferredTimescale: 0)
        let range = CMTimeRangeMake(start: start, duration: avAsset.duration)
        exportSession.timeRange = range

        exportSession!.exportAsynchronously(completionHandler: {() -> Void in
            DispatchQueue.main.async {
                Utility.stopActivityIndicator()

                switch self.exportSession!.status {
                case .failed:
                    self.view.makeToast(self.exportSession?.error?.localizedDescription ?? "")
                case .cancelled:
                    self.view.makeToast("Export canceled")
                case .completed:
                    if let url = self.exportSession.outputURL {
                        //Rendered Video URL
                    }
                default:
                    break
                }
            }
        })
    }

答案 2 :(得分:0)

用这样的容器ID替换此行

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

并在您的mainactivity xml中添加framelayout

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    />

答案 3 :(得分:0)

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


<fragment   android:name=com.example.bluelightlite.models.Team"
            android:id="@+id/Team"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent" />