How to find a view for Snackbar in fragment's onCreateView method if I use view binding and navigation component? - kotlin

I'm trying to show a snack bar in fragment's onCreateView method but I don't know what view to passing inside the snack bar.
I'm very confused because I first time use the Navigation component and view binding and maybe is there a problem.
I tried binding.root but I got this exception:
java.lang.IllegalArgumentException: No suitable parent found from the
given view. Please provide a valid view.
After that I tried requireView().rootView as parameter but I also got this exception:
java.lang.IllegalStateException: Fragment XFragment{7a091b5}
(cefa1aef-59c3-4602-bcf1-b36f7d538cf9) id=0x7f0800f7} did not return a
View from onCreateView() or this was called before onCreateView()
MY CODE IN XFragment:
package com.sdsd.sds
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.Navigation
import com.google.android.material.snackbar.Snackbar
import com.sdsd.sds.databinding.FragmentXBinding
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class XFragment : Fragment() {
private var _binding: FragmenXBinding? = null
private val binding get() = _binding!!
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
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? {
_binding = FragmentXBinding.inflate(inflater, container, false)
binding.tvFgRegistration.setOnClickListener {
Navigation.findNavController(binding.root)
.navigate(R.id.action_f1_to_f2)
}
val snackbar: Snackbar = Snackbar.make(binding.root, "Succesful", Snackbar.LENGTH_LONG)
snackbar.show()
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
XFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
XML LAYOUT FILE:
<?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"
android:background="#drawable/ic"
tools:context=".XFragment">
<EditText
android:id="#+id/etE"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:background="#color/translucent"
android:drawableStart="#drawable/ic_vector"
android:drawablePadding="5dp"
android:ems="10"
android:hint="#string/e_mail"
android:inputType="text"
android:textSize="25sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView" />
<EditText
android:id="#+id/etP"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:background="#color/translucent"
android:drawableStart="#drawable/ic_vector"
android:drawablePadding="5dp"
android:ems="10"
android:hint="#string/password"
android:inputType="textPassword"
android:textSize="25sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/etE" />
<TextView
android:id="#+id/tvFgRegistration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="180dp"
android:layout_marginEnd="76dp"
android:layout_marginBottom="100dp"
android:text="#string/new_u"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I only want to show a snack bar with a message when XFragment creates.
Can anyone tell me how to solve this and explain me in a few words why?

I found few ways to show a snack bar from a fragment
One of the solution is to use requireView().
Snackbar.make(
requireView(),
"Hello from Snackbar",
Snackbar.LENGTH_SHORT
).show()
This solution will work when you are inside any onClickListner{} you can simply pass it as a view and it will do the job.
binding.button.setOnClickListener {
Snackbar.make(
it,
"Hello from Snackbar",
Snackbar.LENGTH_SHORT
).show()
}

I found a simple solution and seems a Snackbar works excellent only with CoordinatorLayout as root layout so I set CoordinatorLayout as my root layout in the XML file.
In the Snackbar I just put binding.coordinatorlayout where coordinatorlayout is just an id of CoordinatorLayout in the XML file.
Code solution for a fragment is here:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentXBinding.inflate(inflater, container, false)
binding.tvFgRegistration.setOnClickListener {
Navigation.findNavController(binding.root)
.navigate(R.id.action_f1_to_f2)
}
val snackbar: Snackbar = Snackbar.make(binding.coordinatorlayout, "Succesful", Snackbar.LENGTH_LONG)
snackbar.show()
return binding.root
}
XML layout file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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:id="#+id/coordinatorlayout" //ID OF COORDINATOR LAYOUT
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ic"
tools:context=".XFragment" >
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ic_backg">
<EditText
android:id="#+id/etE"
android:layout_width="0dp"
.
.
.
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

I faced the same issue while using navigation architecture.
What worked for me was
if(isAdded){
Snackbar.make(requireActivity.window.decorView.rootView,"message").show()
}

Related

how to use findNavController properly in fragment? android studio(kotlin)

when i tried that code in main activity it worked perfectly without any errors. But when i moved code from main activity to mine fragment kt file got some errors. Any solutions?
Here is my kt files:
class MainFragment : Fragment(R.layout.fragment_main) {
private lateinit var bottomNavigationView: BottomNavigationView
private lateinit var navController: NavController
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomNavigationView = view.findViewById(R.id.bottomNavView)
navController = findNavController(R.id.nav_host_fragment)
}
}
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragments.MainFragment">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottomNavView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>

Kotlin WebView refresh button

i googled a bit how to make a refresh button but i didn't really figured out how to make it. I already have the button in my activity_main but nothing in my MainActivity.kt yet. So my problem is now the function of the button to refresh the page again.
This is my Activity_main.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=".MainActivity">
<WebView
android:id="#+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:text="REFRESH"
android:id="#+id/button"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
And this is my MainActivity.kt
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Button
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webview)
webView.settings.setJavaScriptEnabled(true)
webView.setInitialScale(1);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setSupportZoom(true);
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
if (url != null) {
view?.loadUrl(url)
}
return true
}
}
webView.loadUrl("example.com")
}
}
You can try adding this:
findViewById<Button>(R.id.button).setOnClickListener {
webView.reload()
}

The RecyclerView doesn't retrieve any data from Firebase and doesn't show any data

I just started working with Android Studio, and I've been trying to figure out what's wrong with this code for a few days now. When I run the program it shows nothing, and also there is no errors from Android Studio. I read the posts on the subject, but unfortunately I found nothing appropriate.
This is my activity class.
package ie.wit.donationx.activities
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.firebase.database.*
import ie.wit.donationx.adapters.EventsAdapter
import ie.wit.donationx.databinding.ActivityEventsFeedBinding
import ie.wit.donationx.models.EventData
class EventsFeed : AppCompatActivity() {
lateinit var mDataBase: DatabaseReference
private lateinit var eventList:ArrayList<EventData>
private lateinit var mAdapter: EventsAdapter
private lateinit var binding: ActivityEventsFeedBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_events_feed)
binding = ActivityEventsFeedBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
eventList = ArrayList()
mAdapter = EventsAdapter(this,eventList)
var linearLayoutManager = LinearLayoutManager(this)
binding.recyclerEvents.layoutManager = linearLayoutManager
binding.recyclerEvents.setHasFixedSize(true)
binding.recyclerEvents.adapter = mAdapter
getEventsData()
}
private fun getEventsData() {
mDataBase = FirebaseDatabase.getInstance().getReference("Events")
mDataBase.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (eventSnapshot in snapshot.children) {
val event = eventSnapshot.getValue(EventData::class.java)
eventList.add(event!!)
}
binding.recyclerEvents.adapter = mAdapter
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
This is my Adapter
package ie.wit.donationx.adapters
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import ie.wit.donationx.R
import ie.wit.donationx.databinding.ItemListBinding
import ie.wit.donationx.models.EventData
class EventsAdapter(
var c: Context, var eventList: ArrayList<EventData>)
: RecyclerView.Adapter<EventsAdapter.EventViewHolder>() {
inner class EventViewHolder(var v: ItemListBinding): RecyclerView.ViewHolder(v.root){}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
val infilter = LayoutInflater.from(parent.context)
val v = DataBindingUtil.inflate<ItemListBinding>(
infilter,R.layout.item_list,parent,
false
)
return EventViewHolder(v)
}
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
val newList = eventList[position]
holder.v.isEvent = eventList[position]
holder.adapterPosition
}
override fun getItemCount(): Int {
return eventList.size
}
}
XML recyclerView
<?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=".activities.EventsFeed">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/main_shapeable"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="10dp"
android:background="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/main_search"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:ems="10"
android:hint="search"
android:inputType="textPersonName"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="#+id/main_shapeable"
app:layout_constraintEnd_toEndOf="#+id/main_shapeable"
app:layout_constraintStart_toStartOf="#+id/main_shapeable"
app:layout_constraintTop_toTopOf="#+id/main_shapeable" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerEvents"
tools:listitem="#layout/item_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/main_shapeable"/>
</androidx.constraintlayout.widget.ConstraintLayout>
XML file for items in recyclerView
<?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">
<data>
<variable
name="isEvent"
type="ie.wit.donationx.models.EventData" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_margin="10dp"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/eventImg"
android:imageUrl="#{isEvent.image}"
android:scaleType="centerCrop"
android:layout_width="140dp"
android:layout_height="140dp"/>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/eventTitle"
android:textColor="#color/black"
android:textSize="20sp"
android:gravity="center"
android:textStyle="bold|normal"
android:layout_gravity="center"
android:text="#{isEvent.evenTitle}"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/eventInfo"
android:textColor="#android:color/darker_gray"
android:textSize="15sp"
android:gravity="center"
android:textStyle="bold|normal"
android:layout_gravity="center"
android:text="#{isEvent.info}"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
<View
android:background="#android:color/darker_gray"
android:layout_width="match_parent"
android:layout_height="1dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
Data file
package ie.wit.donationx.models
class EventData {
var evenTitle: String? = null
var info: String? = null
var image: String? = null
constructor(){}
constructor(
evenTitle:String?,
info:String?,
image:String?
){
this.evenTitle = evenTitle
this.info = info
this.image = image
}
}
Firebase DB structure
When adding new list to the RecyclerView Adapter you need to call NotifyDataSetChanged()
Also, i advise to remove the list from the constructor of the adapter, and make a public function inside the adapter class that will update the private list created in the class.
private var items: MutableList<EventData> = mutableListOf()
fun setItems(newItemsList : List<EventData>){
eventList.clear()
eventList.addAll(newItemsList)
notifyDataSetChanged()
}
If you only update part of the list, you can create a separate function for that and use the more efficient notifyItemRangeInserted(), notifyItemInserted() or notifyItemChanged() \ notifyItemRangeChanged
You don't need to setAdaper again after getting EventsData
Just replace this line in getEventsData() :
binding.recyclerEvents.adapter = mAdapter
With :
if (eventList.size > 0) {
mAdapter.notifyDataSetChanged()
}
Edit:
You should not to add
android:imageUrl="#{isEvent.image}" in the ImageView,
you can use library to download the images from URL Like:
Picasso.
or
Fresco.
For Example using Picasso in your adapter:
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
val newList = eventList[position]
holder.v.isEvent = eventList[position]
holder.adapterPosition
// here to download image for URL
Picasso.get().load(eventList[position].image)
.into(holder.v.eventImg)
}
Don't forget to add dependencies
implementation 'com.squareup.picasso:picasso:2.8'

Fragment displaying a grey field

I am still a bit new to fragments in android studio but I was wondering if this is usually how fragments are displayed as on the phone. It appear as a grey background above my activity, as shown in this image: https://gyazo.com/9d5569718c5092debfeaab1c631b0046
This is my MainAppActivity code:
class MainAppActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainAppBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainAppBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.appBarMainApp.toolbar)
binding.appBarMainApp.fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_main_app)
// 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_app, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_main_app)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
Any buttons or similar seems to also be affected by it.
Is this normal or is it some sort of bug?
My content_main_app, this is my home set fragment:
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main_app">
<fragment
android:id="#+id/nav_host_fragment_content_main_app"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
Fragment 1:
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
return binding.root
}
}
XML layout fragment 1:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<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=".HomeFragment"
android:background="#android:color/transparent"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Fragment 2:
class HobbiesFragment : Fragment() {
private var _binding: FragmentHobbiesBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val hobbiesViewModel =
ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentHobbiesBinding.inflate(inflater, container, false)
val root: View = binding.root
val textView: TextView = binding.mainTitle
hobbiesViewModel.text.observe(viewLifecycleOwner) {
textView.text = it
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
XML layout fragment 2:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/beige1"
tools:context=".ui.Hobbies.HobbiesFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/mainTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HOBBIES"
android:textColor="#color/blueMix"
android:textSize="38sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.043" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.097"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mainTitle"
app:layout_constraintVertical_bias="0.064" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Fragment 3:
class GalleryFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val galleryViewModel =
ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root
val textView: TextView = binding.textGallery
galleryViewModel.text.observe(viewLifecycleOwner) {
textView.text = it
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
XML layout fragment 3:
<?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=".ui.gallery.GalleryFragment">
<TextView
android:id="#+id/text_gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
After a few hours of messing around in android studio I finally found out what was giving me a grey background, covering the main fragment. I had to go into my main activity ( mainAppActivity in my case ) and delete the material divider (as seen in the image). It solved the problem for me.

Why is my FloatingActionButton doesn't work on Fragment in Kotlin?

I have created a FloatingActionButton to switch the view between gridView and listView of the recyclerView in an fragment. I just wanted to make sure that the FloatingActionButton works correctly and So I just added a `toast. However, the toast doesn't show up when I hit the button.
fragment_dashboard.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"
android:background="#color/colorOffWhite"
tools:context=".ui.fragments.DashboardFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_dashboard_items"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fb_dashboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginBottom="60dp"
android:backgroundTint="#color/colorAccent"
android:clickable="true"
android:focusable="true"
android:src="#drawable/ic_grid_list_view"
app:layout_anchorGravity="bottom|right|end"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="#+id/tv_no_dashboard_items_found"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="#string/no_dashboard_item_found"
android:textAlignment="center"
android:textSize="#dimen/no_data_found_textSize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
DashboardFragment.kt
class DashboardFragment : BaseFragment() {
private var binding: FragmentDashboardBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding?.fbDashboard?.setOnClickListener { view ->
Toast.makeText(requireContext(), "You clicked FA Button", Toast.LENGTH_LONG).show()
}
val root = inflater.inflate(R.layout.fragment_dashboard, container, false)
return root
}
}
I get the following error when I use the code in the first answer.
You should assign the binding variable using the DatabindingUtil inflate
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(
inflater, R.layout.fragment_dashboard, container, false
)
binding?.fbDashboard?.setOnClickListener { view ->
Toast.makeText(requireContext(), "You clicked FA Button", Toast.LENGTH_LONG).show()
}
return binding.root
}
Also, wrap the layout file fragment_dashboard in a layout tag.
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
</layout>
This is what I used and resolved the issue.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDashboardBinding.inflate(inflater, container, false)
binding.fbDashboard.setOnClickListener {
Toast.makeText(requireContext(), "You clicked FA Button", Toast.LENGTH_LONG).show()
}
return binding.root
}