How to provide conditional Up and Back navigation when using Android's Navigation Component library?
For example, my app has a contact book. When creating a new contact, if the user presses back before filling out any info, I'd like to go back to the list of contacts. If the user filled out info, I'd like to go to the detail view of that contact.
In your fragment's onCreate, add an OnBackPressedCallback callback:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(this) {
backOrUpPressed()
}
}
Then, after you setup your toolbar with the NavController, set a NavigationOnClickListener:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Setup the view
setSupportActionBar(toolbar)
toolbar.setupWithNavController(findNavController(), AppBarConfiguration(findNavController().graph))
toolbar.setNavigationOnClickListener { backOrUpPressed() }
}
Then implement your custom Up/Back logic in backorUpPressed()
Related
Im using Compose via ComposeView in a Fragment backed by Graph Navigation.
Im using ModalBottomSheetLayout and need to hide it on back Press.
I have tried using BackHandler, but it is not working.
class fragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
BackHandler(true) {
Log.i("compose_check","back Pressed") // not getting triggered
}
}
}
}
}
I have Overrided onBackPressed() in the Activity. After removing that, it worked fine.
I have a bunch of popup Dialogs throughout the app I'm working on. What I wanted to do is turn them all into a BottomSheet presentation. Right now, I have one class where I'm instantiating the Dialogs from and able to reuse them throughout the app.
What would I need to do: to do the same to be able to reuse BottomSheetDialogFragments? Rather than creating a BottomSheet presentation from a screen to screen basis, is there a way to have all of them in one class and just call them when I need to from a different screen?
Adding a little bit more context. Let's say I have a CloseDialog, LogoutConfirmationDialog and I use them on multiple screens currently. I would like to do the same with the Android BottomSheet presentation modal if I was to turn these two Dialogs into a BottomSheet presentation.
You can create a custom fragment and inherit "BottomSheetDialogFragment"
class CustomBtmSheetFragment : BottomSheetDialogFragment()
{
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View?
{
return inflater.inflate(
R.layout.fragment_dialog,
container,
false
)
}
override fun getTheme(): Int = R.style.CustomBottomSheetDialog
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
BottomSheetDialog(requireContext(), theme)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
}
I'm creating a shopping app where the user can choose next product from the fragment. That will open the next fragment of the same class with more products and so on. I want to use swipe to dismiss behaviour, so when I swipe my finger down I dissmiss the current fragment. It's essential that while swiping the current fragment the user will be able to see the fragment underneath, so I can only use add instead of replace. Here's the problem: When I use add in my fragment manager, the created fragments UI's overlap, which makes the user swipe multiple fragments at once and not show swiping animation. The fragment uses one xml layout so it shares id across all fragments so I have no way of controlling which layouts are disabled. How do I make the user only swipe one fragment/disable touching fragments underneath? The swipe to dissmis is working well with replace but that's not the point. Here's my code.
Activity:
class PullDismissActivity : AppCompatActivity(), PullDismissLayout.Listener {
private lateinit var viewModel: StackingFragmentsViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pulldismiss)
viewModel = ViewModelProvider(this).get(StackingFragmentsViewModel::class.java)
supportFragmentManager.beginTransaction()
.add(R.id.pull, SwipeFragment(), null)
.addToBackStack(null) // name can be null
.commit()
val layout = findViewById<PullDismissLayout>(R.id.pull)
layout.setListener(this)
}
override fun onDismissed() {
viewModel.popBackStack()
supportFragmentManager.popBackStack()
}
override fun onShouldInterceptTouchEvent(): Boolean {
return false
}
Fragment:
class SwipeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val viewModel = ViewModelProvider(requireActivity()).get(StackingFragmentsViewModel::class.java)
viewModel.addFragment(this.hashCode())
val fragid = view.findViewById<TextView>(R.id.fragid)
fragid?.text = System.currentTimeMillis().toString()
val button = view.findViewById<Button>(R.id.button)
button.setOnClickListener {
requireActivity().supportFragmentManager.beginTransaction()
.add(R.id.pull, SwipeFragment(), null)
.addToBackStack(null)
.commit()
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment,container,false)
}
Im currently working on an app, which has a BottomSheetDialog as navigation menu. This menu, is called by the Toolbar Navigation Item.
When calling the BottomSheetDialog, it shows up, and clicking on an item of the list creates the related activity, which is expected. However, when i close the newly opened activity the BottomSheetDialog shows up again, which is not the intended behaviour.
Are there any ways to prevent the BottomSheetFragment to show up?
I tried using .also after the creation of the Intent, but there are no function dedicated to hide or close the Dialog
Here is the BottomSheetFragment code:
class frgBottomSheetDrawer : BottomSheetDialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_bottomsheet, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
navDrawer.setNavigationItemSelectedListener { menuItem ->
when (menuItem!!.itemId) {
R.id.ndListFolder -> this.startActivity(Intent(activity, ndActFolder::class.java))
R.id.ndListSettings -> this.startActivity(Intent(activity, ndActSettings::class.java))
R.id.ndListAbout -> this.startActivity(Intent(activity, actAbout::class.java))
}
true
}
}
}
To close the bottomSheet Dialog after an Item Click , try the following
navDrawer.setNavigationItemSelectedListener { menuItem ->
when (menuItem!!.itemId) {
R.id.ndListFolder -> this.startActivity(Intent(activity,
ndActFolder::class.java))
dismiss() // add this whenever you want to close the bottomSheet
}
true
}
So you simply need to add this method dismiss()
I need to make a custom behaviour, when the user press the back button then the user will go to certain destination programatically. I actually have read this Handling back button in Android Navigation Component
but I don't understand how to use that custom back button code.it seems weird to me.
I have tried using this code below
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
fragmentView = inflater.inflate(R.layout.fragment_search_setting, container, false)
// set custom back button
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// navigate to certain destination
Navigation.findNavController(fragmentView).popBackStack(R.id.destination_create_event, false)
}
return fragmentView
}
but I get type mismatch error like this
You must create new Instance of the OnBackPressedCallback abstract class and implement its abstract method .
I hope this helps you:
val callback = requireActivity().onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true){
override fun handleOnBackPressed() {
Navigation.findNavController(fragmentView).popBackStack(R.id.destination_create_event, false)
}
})
// The callback can be enabled or disabled here or in the lambda
}