简体   繁体   中英

Kotlin - Open other fragment on click CardView in another fragment

I'm new in Android Studio and having trouble opening fragment on click CardView in other fragment. I have Navigation View in layout and navigate to other fragment (fragment_home, fragment_gallery, fragment_slideshow, and other fragment layout.). But I have to create CardView in fragment_home to click for open some fragment layout (Gallery and Slideshow).

I have layout:

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>

And Kotlin code,

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
    }
}

How to implement action for CardView click to open other fragment?, Please help and Thank for your any solution. Thanks.

You need to open another fragment here. For this you need to replace the fragment container in MainActivity with the desired fragment.

Replace this

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

with this

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

I hope this will work for you.

Happy Coding :)

You're just trying to inflate the fragment_gallery inside your homeFragment. I don't think it's the right way to do it. Although, I'll suggest the approach I use.

Inside your activity_main.xml add the FrameLayout. which will be useful to add/replace the desired fragment into it.

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

Now in your Activity, create the following function. It will help you to replace the desired fragment.

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

Now, inside onCreate load the homeFragment (as it is your first fragment to show)

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

At this stage, you'll be able to load homeFragment successfully. Now next step is to create a callback interface. Every time you click on any card from the homeFragment you just have to provide the required information back to the mainActivity. It is good practice to leaving the responsibility of loading fragments on the activity.

interface OnCardClickListener {
    fun onCardClick(fragment: Fragment)
}

implement this listener in MainActivity.

class MainActivity: OnCardClickListener{

It will override the onCardClick. now inside onCardClick call the replace method.

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

Inside HomeFragment, Create an instance of OnCardClickListener

var listener: OnCardClickListener? = null

then in onAttach.

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

Till this point, we have implemented the mechanism required to load fragment. Now only one final step is pending which is opening the desired fragment onClick of cardView. for that do as follow:

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM