Kotlin - 在另一个片段中单击 CardView 打开另一个片段

Kotlin - Open other fragment on click CardView in another fragment

我是 Android Studio 的新手,在单击其他片段中的 CardView 时无法打开片段。我在布局中有导航视图并导航到其他片段(fragment_home、fragment_gallery、fragment_slideshow 和其他片段布局。)。但我必须在 fragment_home 中创建 CardView 才能单击以打开一些片段布局(画廊和幻灯片)。

我有布局:

1. fragment_home.xml

<?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"
    tools:context=".ui.home.HomeFragment">
    
    <androidx.cardview.widget.CardView
        android:id="@+id/cardOpenGallery"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_margin="20dp">
        
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:background="#ccc">
            
            <TextView
                android:id="@+id/textOpenGallery"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp"
                android:textAlignment="center"
                android:textSize="30sp"
                android:textColor="#000"
                android:text="Open Gallery"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

        </LinearLayout>

    </androidx.cardview.widget.CardView>

</LinearLayout>

2。 fragment_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<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=".ui.gallery.GalleryFragment">

    <!-- other layout element here -->

</FrameLayout>

3。 fragment_slideshow.xml

<?xml version="1.0" encoding="utf-8"?>
<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=".ui.gallery.SlideshowFragment">

    <!-- other layout element here -->

</FrameLayout>

和 Kotlin 代码,

1. MainActivity.kt

import ...

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        val fab: FloatingActionButton = findViewById(R.id.fab)
        fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
        }

        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }
}

2。 HomeFragment.kt

import ...

class HomeFragment : Fragment() {

    private lateinit var homeViewModel: HomeViewModel

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        homeViewModel =
                ViewModelProviders.of(this).get(HomeViewModel::class.java)
        val root = inflater.inflate(R.layout.fragment_home, container, false)
        
        //I have problem here-----
        val myCard1 = root.findViewById(R.id.cardOpenGallery) as CardView
        myCard1.setOnClickListener(object : View.OnClickListener {
            override fun onClick(v: View?) {
                inflater.inflate(R.layout.fragment_gallery, container, false)
            }
        })

        return root
    }

}

3。 GalleryFragment.kt

import ...

class GalleryFragment : Fragment() {

    private lateinit var galleryViewModel: GalleryViewModel

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        galleryViewModel =
                ViewModelProviders.of(this).get(GalleryViewModel::class.java)
        val root = inflater.inflate(R.layout.fragment_gallery, container, false)
        val textView: TextView = root.findViewById(R.id.text_gallery)
        galleryViewModel.text.observe(viewLifecycleOwner, Observer {
            textView.text = it
        })
        return root
    }
}

4. SlideshowFragment.kt

import ...

class SlideshowFragment : Fragment() {

    private lateinit var slideshowViewModel: SlideshowViewModel

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        slideshowViewModel =
                ViewModelProviders.of(this).get(SlideshowViewModel::class.java)
        val root = inflater.inflate(R.layout.fragment_slideshow, container, false)
        val textView: TextView = root.findViewById(R.id.text_slideshow)
        slideshowViewModel.text.observe(viewLifecycleOwner, Observer {
            textView.text = it
        })
        return root
    }
}

如何实现CardView点击打开其他片段的动作?请帮忙,谢谢你的任何解决方案。谢谢。

您需要在此处打开另一个片段。为此,您需要用所需的片段替换 MainActivity 中的片段容器。

替换这个

 myCard1.setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View?) {
            inflater.inflate(R.layout.fragment_gallery, container, false)
        }
    })

有了这个

myCard1.setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View?) {
        ((Activity) getContext).supportFragmentManager.beginTransaction()
        .replace(R.id.fragment_container, GalleryFragment())       
        .commit()
        }
    }) 

我希望这对你有用。

快乐编码:)

您只是想给 homeFragment 中的 fragment_gallery 充气。我认为这不是正确的做法。不过,我会建议我使用的方法。

在您的 activity_main.xml 中添加 FrameLayout。这将有助于 add/replace 将所需的片段放入其中。

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

现在在您的 Activity 中,创建以下函数。它将帮助您替换所需的片段。

private fun replaceFragment(fragmentInstance: Fragment) {
supportFragmentManager
               .beginTransaction()
               .addToBackStack(fragmentInstance.javaClass.canonicalName)//optional
               .replace(R.id.container, fragmentInstance)
               .commit()
}

现在,在 onCreate 中加载 homeFragment(因为这是您要显示的第一个片段)

override fun onCreate(savedInstanceState: Bundle?) {
val fragment = HomeFragment()
replaceFragment(fragment)
}

在此阶段,您将能够成功加载 homeFragment。现在下一步是创建一个回调接口。每次单击 homeFragment 中的任何卡片时,您只需将所需信息提供回 mainActivity。将加载片段的责任留在 activity.

上是一种很好的做法
interface OnCardClickListener {
    fun onCardClick(fragment: Fragment)
}

在 MainActivity 中实现此侦听器。

class MainActivity: OnCardClickListener{

它将覆盖 onCardClick。现在在 onCardClick 中调用 replace 方法。

override onCardClick(fragment: Fragment){
replaceFragment(fragment)
}

在 HomeFragment 中,创建 OnCardClickListener 实例

var listener: OnCardClickListener? = null

然后在 onAttach 中。

override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as OnCardClickListener
    }

至此,我们已经实现了加载片段所需的机制。现在只有最后一步未决,即打开 cardView 的 onClick 所需片段。为此,请执行以下操作:

myCard1.setOnClickListener{
   listener.onCardClick(GalleryFragment())
}

//If there's one more card available.
myCard2.setOnClickListener{
   listener.onCardClick(SlideshowFragment())
}