How to handle back button in case of fragment without removing previous views? - android-fragments

I have one activity (MainActivity) and two fragments(FirstFragment,SecondFragment) as the lifecycle of activity is handled by the os we can press back button and go to previous activity without any hassle . But when I try to go back by pressing back button from one fragment to another fragment although it takes me back to the fragment but removes all my view. Meaning I can't see any element of that fragment . A more detailed explanation is down below with code
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val activity1Button = findViewById<Button>(R.id.activity_1_Button)
activity1Button.setOnClickListener {
supportFragmentManager.beginTransaction()
.replace(R.id.mainActivity, FirstFragment()).addToBackStack(null).commit()
}
}
}
The main activity has a button which can take the user to the next fragment(FirstFragment) while adding it to the BackStack
FirstFragment.kt
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
container?.removeAllViews()
val view = inflater.inflate(R.layout.fragment_first, container, false)
val firstFragmentButton = view.findViewById<Button>(R.id.firstFragmentButton)
firstFragmentButton.setOnClickListener {
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.firsFragment, SecondFragment())
.addToBackStack("tag")
.commit()
}
return view
}
}
Now from this fragment user can go to another fragment (SecondFragment)
SecondFragment.kt
class SecondFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
container?.removeAllViews()
return inflater.inflate(R.layout.fragment_second, container, false)
}
}
However I am removing all the previous container views as without doing this I the elements of previous fragment/ activity is also visible even when I am in a new fragment. Now when once I have pressed buttons to come to SecondFragment and pressing back button to go to FirstFragment I cant see the buttons anymore in the FirstFragment but through the Layout Inspector it is confirmed that I am in the desired fragments layout. What can be done to solve this issue ?
I have tried to implement this method below but it didn't solve my problem .
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
val manager: FragmentManager = requireActivity().supportFragmentManager
if (manager.backStackEntryCount > 0) {
manager.popBackStack()
}
}
})
}
Thanks in advance .

Related

Type mismatch: inferred type is Model but List<Model> was expectedd

I'm using the room library in a Mvvm architecture application.
There is a main piece and a detail piece.
I go to the detail fragment with id. So I pull the ID from the room. But I will use recyclerview in detail fragment. As you know, there is a list in the adapter class. I am also pulling objects from livedata. These two do not overlap. Do you have a suggestion about it?
This is the detail trailer.
I go to the detail fragment by clicking on Home Fragment. Of course, the relevant information in the list I clicked on will be in the detail section. Think of it like a news site. But I'm going to extract the identity from the elaborate fragmentary room. But I will use recylerview in the detail trailer, but pull it out of the room. The ID and list on the adapter do not match.
Output of the error = Type mismatch: inferred type is Int but List was expected
private var uuidd=0
private lateinit var Biewmodell:Bilimdetayviewmodel
private lateinit var bindingdetay:FragmentBdetayBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.let {
uuidd = BdetayFragmentArgs.fromBundle(it).uuidd
}
val viewmodelll:Bilimdetayviewmodel by viewModels()
Biewmodell=viewmodelll
Biewmodell.roomgit(uuidd)
observer()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
bindingdetay=DataBindingUtil.inflate(inflater,R.layout.fragment_bdetay, container, false)
return bindingdetay.root
}
fun observer(){
Biewmodell.getroomlivedata.observe(viewLifecycleOwner, Observer { model ->
model?.let {
val adapterr = dAdapterd(requireContext(),it)
bindingdetay.adapterr=adapterr
}
})
}

Jetpack compose navigation architecture without fragment?

I am a bit confused about the new Jetpack compose navigation component androidx.navigation:navigation-compose documented at https://developer.android.com/jetpack/compose/navigation.
Am I right to say that the single-activity architecture with 0 fragment is preferred to the single-activity architecture with multiple fragments when using Jetpack Compose ?
I know we can still use fragments and Jetpack compose in this manner :
class MyFragment: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply{
setContent {
MyFragmentComposable()
}
}
}
}
But I want to make sure that when using androidx.navigation:navigation-compose, we are not supposed to use fragment anymore, starting like so:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
}
Yes, you are correct. Using no fragments is preferred. You can use a NavHost to declare your navigation graph.

findViewById in Android kotlin Fragment

Normally one does
findViewById<TextView>(R.id.text_view).text = "foo"
but this doesn't work in a fragment.
This seems to work, but it seems rather cumbersome
getView()?.findViewById<TextView>(R.id.text_view)?.text = "foo"
Is it right?
What is one supposed to do in a Fragment (is it documented anywhere)?
An example of binding views in Fragment in Kotlin
var view: View? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_feedback_tab, container, false)
return view
}
Initialized your view inside onCreateView() as shown below:
class HomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
var view: View? = null
view = inflater.inflate(R.layout.fragment_home, container, false)
return view
}

Change Button Background in a Fragment with Kotlin

I'm totally new in kotlin so I don't know how many things I'm doing wrong.
I'm trying to set the button background of a fragment from code, but when I start the application in my phone, there is just the background and an empty button
class start : Fragment() {
override fun onCreateView(Layoutinflater: LayoutInflater,
container: ViewGroup?, savedInstantState: Bundle?):View? {
return Layoutinflater.inflate(R.layout.fragment_start, container, false)
val button_start = view!!.findViewById<Button>(R.id.button_start_1_id)
button_start.setBackgroundResource(R.drawable.button_start1)
}
}
And
<ImageButton
android:id="#+id/button_start_1_id"
android:layout_width="124dp"
android:layout_height="69dp"
android:onClick="button_start_pushed">
</ImageButton>
I'm also new in this forum so if a doing something wrong please let me know
Welcome to stackoverflow.
Answer to your question is a simple one. First of all you do not explicitly need to get reference to your view using the following code, and it is redundant.
val button_start = view!!.findViewById<Button>(R.id.button_start_1_id)
You can easily get the reference to your view / imageview using view's id. In your case, and you can just call background property in your view class and set the background using resource.getDrawable(R.drawable.button_start1)
If your API level 16 or above, you can use the following code.
class ImageFragment : Fragment(){
override fun onCreateView(Layoutinflater: LayoutInflater,
container: ViewGroup?, savedInstantState: Bundle?): View? {
return Layoutinflater.inflate(R.layout.fragment_start, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button_start.background = resources.getDrawable(R.drawable.button_start1)
}
}
resources.getDrawable gives deprecation warning in Kotlin because it requires Resource.Theme as second parameter. If you have Resource.Theme, give it as a second parameter.
And your layout would be the following:
<ImageButton
android:id="#+id/button_start"
android:layout_width="124dp"
android:layout_height="69dp"
android:onClick="button_start_pushed">
</ImageButton>
If you are using API level below 16, then you could use the following code:
class ImageFragment : Fragment(){
override fun onCreateView(Layoutinflater: LayoutInflater,
container: ViewGroup?, savedInstantState: Bundle?): View? {
return Layoutinflater.inflate(R.layout.fragment_start, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button_start.setImageResource(R.drawable.button_start1)
}
}
Just make sure you have button_start1 icon or img in your drawable, and your layout name is correct.
Another things to note: it would be a lot easier for you to have your own consistent naming convention, or at least follow the recommended one by Kotlin or Java.
I hope it helps you!

Error calling setSupportActionBar in a Fragment in Kotlin

I am trying to set up a toolbar in a fragment.
Whilst the Google Developer docs have been updated to include Kotlin code (see this page):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my)
// Note that the Toolbar defined in the layout has the id "my_toolbar"
setSupportActionBar(findViewById(R.id.my_toolbar))
it relates to the setup of a toolbar in an activity as opposed to a fragment.
I found this SO post which suggests that you can't just call setSupportActionBar in a fragment. To quote:
Fragments don't have such method setSupportActionBar(). ActionBar is a
property of Activity, so to set your toolbar as the actionBar, your
activity should extend from ActionBarActivity and then you can call in
your Fragment:
...
If you're using AppCompatActivity:
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);
However the code given above is in java.
How do I call this in Kotlin?
To access the ActionBar from a Fragment in Kotlin:
if(activity is AppCompatActivity){
(activity as AppCompatActivity).setSupportActionBar(mToolbar)
}
To set an ActionBar title from a Fragment you can do
(activity as AppCompatActivity).supportActionBar?.title = "Title"
or
(activity as AppCompatActivity).supportActionBar?.setTitle(R.string.my_title_string)
There is an implementation in the Navigation codelab from Google that I think will do what I need: enable customisation of the title, menu items and hook into the up navigation for different fragment contexts. Specifically:
The toolbar is included in the main layout xml file (navigation_activity.xml in that codelab) outside of the fragment:
navigation_activity.xml
<LinearLayout>
<android.support.v7.widget.Toolbar/>
<fragment/>
<android.support.design.widget.BottomNavigationView/>
</LinearLayout>
Then setup the toolbar in the main activity file as follows:
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var drawerLayout: DrawerLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.navigation_activity)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
//...
// Set up Action Bar
val navController = host.navController
setupActionBar(navController)
//...
}
private fun setupActionBar(navController: NavController) {
drawerLayout = findViewById(R.id.drawer_layout)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val retValue = super.onCreateOptionsMenu(menu)
val navigationView = findViewById<NavigationView>(R.id.nav_view)
// The NavigationView already has these same navigation items, so we only add
// navigation items to the menu here if there isn't a NavigationView
if (navigationView == null) {
menuInflater.inflate(R.menu.menu_overflow, menu)
return true
}
return retValue
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Have the NavHelper look for an action or destination matching the menu
// item id and navigate there if found.
// Otherwise, bubble up to the parent.
return NavigationUI.onNavDestinationSelected(item,
Navigation.findNavController(this, R.id.my_nav_host_fragment))
|| super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(drawerLayout,
Navigation.findNavController(this, R.id.my_nav_host_fragment))
}
}
Then in the fragment file you can inflate further menu items. In the codelab, main_menu.xml contains a shopping cart item which is added to the overflow setup in the main activity above.
MainFragment.kt
class MainFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true)
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.main_menu, menu)
}
}

Resources