Kotlin - Open other fragment on click CardView in another fragment - java

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

Related

Can we write UI in activity xml as well UI in fragment xm?

I have create an activity and have 2 buttons. On click of each button fragment opens.
But when I do that fragment UI gets overlapped with activity UI.
I want to know if we can have UI components in both activity and fragment.
Also if have to keep the activity UI blank and create a new fragment from the activity for the UI.
Please let me kow how I can solve this.
Example of the code :
MainActivity.kt
override fun onClick(view: View?) {
Log.d(TAG, "onClick: ")
when(view!!.id){
R.id.song_list->
{
Toast.makeText(this, "Songs list will be shown", Toast.LENGTH_SHORT).show()
openFragment("Songs")
}
R.id.artist_list->
{
Toast.makeText(this, "Artist list will be shown", Toast.LENGTH_SHORT).show()
openFragment("Artist")
}
}
}
fun openFragment(fragmentName: String){
Log.d(TAG, "openFragment: ")
if(fragmentName.equals("Songs")) {
val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.main_fragment, SongsFragment())
transaction.disallowAddToBackStack()
transaction.commit()
}else{
val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.main_fragment, ArtistFragment())
transaction.commit()
}
}
MainActivity XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<FrameLayout
android:id="#+id/main_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/song_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Songs List"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="#+id/artist_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Artist List"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/song_list"
android:layout_marginTop="5dp"/>
SongsFragment.kt
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate: ")
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_songs, container, false)
Log.d(TAG, "onCreateView: ")
}
SongsFragment XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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=".SongsFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Please find the list of songs here" />
</androidx.constraintlayout.widget.ConstraintLayout>
As i can see you are missing some constrains on the Frame Layout that holds your fragments, if you set it as you like you can have your buttons and the fragment of your choice at the same time.

Child RecyclerView doesn't scroll internally

I'm kinda new to Android App Development. Well, I'm playing around with RecyclerView. I have a parent recyclerview with a modal layout. Now the modal layout has a recyclerview (child recyclerview). I have managed to create adapters and scroll the list of main recyclerview. Unfortunately I don't find a way to scroll the child recyclerview. Here is the code that I'm playing around:
I've already tried setting the adapter of child recyclerview in onBindViewHolder method of parent recyclerview adapter.
Also, I tried setting the attributes nestedScrollingEnabled=true, descendantFocusability=blocksDescendants and focusableInTouchMode=true for child recyclerView.
Here's my activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Parent recyclerview model (model.xml):
<?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="wrap_content"
android:layout_margin="16dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="Testing" />
<View
android:layout_width="wrap_content"
android:layout_height="1dp"
android:background="#android:color/darker_gray"
android:layout_marginVertical="8dp"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/modalRecyclerView"
android:layout_width="wrap_content"
android:layout_height="100dp" />
</LinearLayout>
Child recyclerview model (child_modal.xml):
<?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="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Testing"/>
</LinearLayout>
In the MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView.apply {
layoutManager = LinearLayoutManager(this#MainActivity, RecyclerView.VERTICAL, false)
adapter = ModalAdapter()
}
}
ModalAdapter:
class ModalAdapter : RecyclerView.Adapter<ModalAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context).inflate(R.layout.model, parent, false)
return ViewHolder(inflater)
}
override fun getItemCount(): Int {
return 5
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.view.modalRecyclerView.adapter = ChildModalAdapter()
holder.view.modalRecyclerView.layoutManager = LinearLayoutManager(holder.view.context, RecyclerView.VERTICAL, false)
}
class ViewHolder(val view: View): RecyclerView.ViewHolder(view)
}
ChildModalAdapter:
class ChildModalAdapter : RecyclerView.Adapter<ChildModalAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context).inflate(R.layout.child_modal, parent, false)
return ViewHolder(inflater)
}
override fun getItemCount(): Int {
return 10
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
}
class ViewHolder(val view: View): RecyclerView.ViewHolder(view)
}
Internal recyclerview doesn't scroll while the parent recyclerview scrolls fine. I'm trying to find a way to make the internal recyclerview to scroll along with parent recyclerview (I want both the recyclerviews to scroll).
Okay, I fixed this by setting a listener.
Here's the code below that fixed it:
val mScrollChangeListener = object : RecyclerView.OnItemTouchListener {
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
when (e.action) {
MotionEvent.ACTION_MOVE -> {
rv.parent.requestDisallowInterceptTouchEvent(true)
}
}
return false
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
modalRecyclerView.addOnItemTouchListener(mScrollChangeListener)
I've added this code in the onBindViewHolder() of parent RecyclerView's adapter.

onClick event in navigation drawer does not work

Disclaimer: I already read the post at onClick event in navigation drawer, but sadly it does not work for me.
I am pretty new to Android I am just making my first app in Kotlin and I wanted to integrate an NavigationDrawer. In it I have integrated an option "Website" which should just launch a website. Just when I click on it it closes the drawer, but does not start the Intent for the website.
My Code: (I removed unimportant parts that are needed for the rest of the app)
MainActivity.kt:
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var drawerLayout: DrawerLayout
private lateinit var aToggle: ActionBarDrawerToggle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(activity_main)
createNotificationChannel()
setNavigationViewListener()
val toolbar: Toolbar = toolbar
setSupportActionBar(toolbar)
val actionbar: ActionBar? = supportActionBar
actionbar?.apply {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.ic_menu)
}
drawerLayout = drawer_layout
aToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open, R.string.close)
drawerLayout.addDrawerListener(aToggle)
drawerLayout.addDrawerListener(
object : DrawerLayout.DrawerListener {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
}
override fun onDrawerOpened(drawerView: View) {
}
override fun onDrawerClosed(drawerView: View) {
}
override fun onDrawerStateChanged(newState: Int) {
}
}
)
aToggle.syncState()
val navigationView: NavigationView = findViewById(R.id.nav_view)
navigationView.setNavigationItemSelectedListener { menuItem ->
// set item as selected to persist highlight
menuItem.isChecked = true
// close drawer when item is tapped
drawerLayout.closeDrawers()
// Add code here to update the UI based on the item selected
// For example, swap UI fragments here
true
}
}
private fun setNavigationViewListener() {
val navigationView = nav_view
navigationView.setNavigationItemSelectedListener(this)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.drawer_view, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
drawerLayout.openDrawer(GravityCompat.START)
true
}
else -> super.onOptionsItemSelected(item)
}
if(aToggle.onOptionsItemSelected(item)) {
return true
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.website -> {
val i = Intent(Intent.ACTION_VIEW).setData(Uri.parse("http://gym-wen.de/vp/"))
startActivity(i)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
else -> {}
}
return true
}
}
activity_main.xml:
<?xml version="1.0" encoding="UTF-8"?>
<android.support.v4.widget.DrawerLayout
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:id="#+id/drawer_layout"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar" />
<ListView
android:id="#+id/vertretungs_list"
android:paddingTop="?attr/actionBarSize"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/drawer_view" />
drawer_view.xml (menu):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="#+id/website"
android:title="#string/website" />
<item
android:id="#+id/nav_gallery"
android:title="2" />
<item
android:id="#+id/nav_slideshow"
android:title="3" />
<item
android:id="#+id/nav_manage"
android:title="4" />
</group>
I am pretty sure I forgot something, but I just do not know what it is. I read many tutorials and other posts, but I just do not know it. Hopefully someone can help me :)
Greetings
You have set two listeners for the same things. One overwrites the other.
navigationView.setNavigationItemSelectedListener { menuItem ->
// set item as selected to persist highlight
menuItem.isChecked = true
// close drawer when item is tapped
drawerLayout.closeDrawers()
// Add code here to update the UI based on the item selected
// For example, swap UI fragments here
true
}
Which does not launch the website and navigationView.setNavigationItemSelectedListener(this) which should.
I were you I would remove the entire first block and implement everything in override fun onOptionsItemSelected(item: MenuItem): Boolean
Your activity class implements NavigationView.OnNavigationItemSelectedListener,
so instead of setting as a listener:
navigationView.setNavigationItemSelectedListener { menuItem ->
// set item as selected to persist highlight
menuItem.isChecked = true
// close drawer when item is tapped
drawerLayout.closeDrawers()
// Add code here to update the UI based on the item selected
// For example, swap UI fragments here
true
}
you should call:
navigationView.setNavigationItemSelectedListener(this)
so this method is called:
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.website -> {
val i = Intent(Intent.ACTION_VIEW).setData(Uri.parse("http://gym-wen.de/vp/"))
startActivity(i)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
else -> {}
}
return true
}
and in this method you manipulate the closing of the drawer or the checked items.

Cannot uniquely identify layout when adding nested fragments with fragmenttransaction

I am trying to do the following:
In activity, replace the container with a fragment (TestFragment)
This fragment's layout contains a container which is replaced by another fragment (TestSubFragment)
Clicking on the TestSubFragment makes the activity add a new TestFragment over the root container
TestActivity.kt
class TestActivity : AppCompatActivity(), TestSubFragment.OnFragmentInteractionListener {
override fun onFragmentInteraction(id: Int) {
supportFragmentManager.beginTransaction().add(R.id.container, TestFragment.newInstance(id)).addToBackStack(null).commit()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
supportFragmentManager.beginTransaction().replace(R.id.container, TestFragment.newInstance(1)).addToBackStack(null).commit()
}
}
TestFragment.kt
class TestFragment : Fragment() {
private var id: Int? = null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater!!.inflate(R.layout.fragment_test, container, false)
activity.supportFragmentManager.beginTransaction().replace(R.id.sub_fragment_container, TestSubFragment.newInstance(id!!)).commit()
return v
}
companion object {
fun newInstance(id: Int): TestFragment {
val fragment = TestFragment()
fragment.id = id
return fragment
}
}
}
TestSubFragment.kt
class TestSubFragment : Fragment() {
private var mListener: OnFragmentInteractionListener? = null
private var id: Int? = null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater!!.inflate(R.layout.fragment_sub_test, container, false)
v.id_text.text = id.toString()
v.id_text.setOnClickListener { _ -> mListener?.onFragmentInteraction(v.id_text.text.toString().toInt() + 1) }
return v
}
override fun onAttach(context: Context?) {
super.onAttach(context)
if (context is OnFragmentInteractionListener) {
mListener = context
}
}
interface OnFragmentInteractionListener {
fun onFragmentInteraction(id: Int)
}
companion object {
fun newInstance(id: Int): TestSubFragment {
val fragment = TestSubFragment()
fragment.id = id
return fragment
}
}
}
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="ckl.happens.TestActivity">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
fragment_test.xml
<FrameLayout 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"
android:background="#ffffff"
tools:context="ckl.happens.TestFragment">
<FrameLayout
android:id="#+id/sub_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</FrameLayout>
fragment_sub_test.xml
<FrameLayout 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"
android:background="#ffffff"
tools:context="ckl.happens.TestFragment">
<TextView
android:id="#+id/id_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
</FrameLayout>
Problem is that the replace fragment line in TestFragment.kt is finding the first R.id.sub_fragment_container from the xml hierarchy so it is replacing the incorrect container instead of the last/new container.
I tried adding tag in fragmenttransaction or change R.id.sub_fragment_container to v.sub_fragment_container.id but no luck.
I don't want to change add() to replace() in onFragmentInteraction because the fragment will be recreated and I want to keep everything in the fragment unchanged when the user back to that fragment.
I can't find detailed article on nesting fragments for my case.
I am working with Kotlin but I can also understand Java. Thank you!
I solved my problem without getting the new container id.
I decided to remove fragmenttransaction and add the fragment in the xml. Then in the fragment (parent fragment) that contains the sub-fragment, get the sub-fragment with childFragmentManager.findFragmentById(R.id.fragment). Finally update the content of the sub-fragment from the parent fragment.
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
val fragment1 = TestFragment.newInstance(1)
supportFragmentManager.beginTransaction().replace(R.id.container, fragment1).commit()
val fragment2 = TestFragment.newInstance(2)
supportFragmentManager.beginTransaction().add(R.id.container, fragment2).addToBackStack(null).commit()
val fragment3 = TestFragment.newInstance(3)
supportFragmentManager.beginTransaction().add(R.id.container, fragment3).addToBackStack(null).commit()
}
}
class TestFragment : Fragment() {
private var id: Int? = null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater!!.inflate(R.layout.fragment_test, container, false)
val subFragment = childFragmentManager.findFragmentById(R.id.fragment) as TestSubFragment
subFragment.view?.findViewById<TextView>(R.id.id_text)?.text = id.toString()
return v
}
companion object {
fun newInstance(id: Int): TestFragment {
val fragment = TestFragment()
fragment.id = id
return fragment
}
}
}
class TestSubFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_sub_test, container, false)
}
}
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="ckl.happens.TestActivity">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
fragment_test.xml
<FrameLayout 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"
android:background="#ffffff"
tools:context="ckl.happens.TestFragment">
<fragment
android:id="#+id/fragment"
android:name="ckl.happens.TestSubFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
fragment_sub_test.xml
<FrameLayout 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"
android:background="#ffffff"
tools:context="ckl.happens.TestFragment">
<TextView
android:id="#+id/id_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="" />
</FrameLayout>

Need to add several fragments in my adapter?

I want to add more Fragment page in my adapt but I do not know how to do.
here is my code adpater with a single Fragment that works without problem.
thank you in advance for your help
class TabAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int) = SampleFragment() //SampleFragment() is my fragment
override fun getCount() = 4
override fun getPageTitle(position: Int) = when (position) {
0 -> "Music"
1 -> "Market"
2 -> "Films"
else -> "Books"
}
}
And this is the code for my SampleFragment()
class SampleFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_sample, container, false)
}
}
Please help me to add each different Fragment for each Pagetitle in Adapter
Here's how to quickly add fragments into your adapter.
You require a ViewPager to hold all fragments you want to display.
Firstly edit your xml as follows.
<RelativeLayout
android:id="#+id/main_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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".MainActivity">
<ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tab_layout" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
</RelativeLayout>
Next Create new fragment and name it Fragment_one.java. Inside here you can do whatever you want like an activity. Create Fragment_two.java or as many as you want and instantiate it in your adapter.
Next create fragmentAdapter.Java and add these code (This is for your custom adapter)
public class fragmentAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public fragmentAdapter(FragmentManager fm, int NumOfTabs){
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
// Add as many fragment in this method
switch (position){
case 0:
Fragment_one frag_one = new Fragment_one ();
return frag_one;
case 1:
Fragment_two frag_two = new Fragment_two ();
return frag_two;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
Next add this inside onCreate() method in your MainActivity.java
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
//add as many fragments you want to add the "fragment 1" & "fragment 2" is
//the title for your fragments, it starts for '0','1','2'...
tabLayout.addTab(tabLayout.newTab().setText("fragment 1"));
tabLayout.addTab(tabLayout.newTab().setText("fragment 2"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final fragmentAdapter adapter = new Adapter(getActivity(),tablayout.geTabCount());
viewPager.setAdapter(adapter);

Categories

Resources