Android 如何用 Kotlin 片段替换 FrameLayout

How to replace a FrameLayout with a fragment with Kotlin on Android

我正在尝试使用 Kotlin 开发 Android 应用程序,但在尝试动态移动片段时遇到了一些障碍。我想要做的是用片段替换 Activity 布局中的 FrameLayout。目前,每当我尝试 运行 我的应用程序时,它只会在工具栏下方显示一个白色屏幕,让我相信片段没有按照我预期的方式添加到 FrameLayout。

这是我的主要 Activity 进行第一笔交易的地方:

package net.ma.ttrobinson.kchan

import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.EditText
import com.androidquery.callback.AjaxStatus
import net.ma.ttrobinson.kchan.api.ChanThread
import net.ma.ttrobinson.kchan.api.Request
import org.jdeferred.DoneCallback
import org.jdeferred.FailCallback
import org.json.JSONArray
import org.json.JSONObject

class MainActivity : AppCompatActivity() {

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

        val toolbar = findViewById(R.id.toolbar) as Toolbar
        setSupportActionBar(toolbar)

        getSupportFragmentManager().beginTransaction()
            .replace(R.id.main_content_frame, MainFragment())
            .commit()
    }
}

这是我要创建的片段。它只是在为按下按钮时添加回调的同时膨胀视图:

package net.ma.ttrobinson.kchan

import android.os.Bundle
import android.support.v4.app.Fragment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import com.androidquery.callback.AjaxStatus
import net.ma.ttrobinson.kchan.api.ChanThread
import net.ma.ttrobinson.kchan.api.Request
import org.jdeferred.DoneCallback
import org.jdeferred.FailCallback

/**
 * Holds the main content
 */
class MainFragment : Fragment() {
    companion object {
        val TAG = "MainFragment"
    }

    val debugBoard = "g"
    val debugThread = "48667796"

    override fun onCreateView(inflater : LayoutInflater, parent : ViewGroup?, savedInstanceState : Bundle?) : View {
        val v = inflater.inflate(R.layout.fragment_main, parent, false)
        val boardText = v.findViewById(R.id.board_text) as EditText
        val threadText = v.findViewById(R.id.thread_text) as EditText
        val request = Request(getActivity())

        boardText.setText(debugBoard)
        threadText.setText(debugThread)

        val button = v.findViewById(R.id.submit) as Button
        button.setOnClickListener({ v ->
            val board = boardText.getText().toString()
            val thread = threadText.getText().toString().toInt()

            val promise = request.getThread(board, thread)
            promise.done({ thread ->
                val fm = getActivity().getSupportFragmentManager()
                fm.beginTransaction()
                    .replace(R.id.main_content_frame, ThreadFragment(thread), ThreadFragment.TAG)
                    .addToBackStack(null)
                    .commit()
            }).fail({ result ->
                Log.v(TAG, "Failed to get thread")
            })
        })

        return v
    }
}

这是主要 Activity 与 setContentView 一起使用的布局:

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

    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />

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

</LinearLayout>

最后是片段展开的布局:

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

    <EditText
        android:id="@+id/board_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/board_hint"/>

    <EditText
        android:id="@+id/thread_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:hint="@string/thread_hint"/>

    <Button
        android:id="@+id/submit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/submit"/>
</LinearLayout>

我觉得这是一个相当简单的主 Activity 设置,它有一个可以与其他片段交换的 FrameLayout。有谁知道我可能做错了什么?

与此同时,我想我会尝试做一个更简单的案例来尝试复制该行为。

编辑:如此简单的解决方案。我忘记在我的 LinearLayout 中添加 android:orientation="vertical"。这是更新后的代码:

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

    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />

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

</LinearLayout>

问题是 Activity 的 LinearLayout 应该有 orientation="vertical":

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

    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />

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

</LinearLayout>

只是想表达您对扩展功能的用意,它非常有用。 在这里我将分享一些步骤

  1. 例如创建一个名为 util 的 kotlin 文件并添加那些允许添加和替换片段的函数

util.kt

fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int){
    supportFragmentManager.inTransaction { add(frameId, fragment) }
}
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int) {
    supportFragmentManager.inTransaction{replace(frameId, fragment)}
}

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
    beginTransaction().func().commit()
}
  1. 创建片段布局。例如,我称之为 father_fragment fahter_fragment

        <!-- You can put whatever you want here--> 
    

  2. 在您的 Activity xml 中创建一个包含片段的布局:

activity_principal.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="com.tharwa.tdm2_exo2.Principal">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/container"
        >
    </FrameLayout>
</android.support.design.widget.CoordinatorLayout>
  1. 现在在 activity 中您可以轻松创建片段

    校长

    class 校长:AppCompatActivity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_principal)
    
            //Create and add the fragment
            val fatherView=FatherPresentation()
            addFragment(fatherView,R.id.container)
        }
    }
    

如果您想替换 activity 中的片段,这很简单 replaceFragment(Fragment_you_want_to_replace_with(),id_of_of_your_frame_layout)