I open a new bottomSheet from a bottomSheet. When service result is successful I call dismiss() and open new fragment. This works most of times but sometimes previous bottomSheet now dismissing. For example when an alertDialog is shown and I close bottom sheet then reopen it and this issue is occurring.
First BottomSheet:
btnSend.click {
viewModel.callServiceFunction()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
observe(viewModel.serviceSuccessLiveData) {
dismiss()
navigator.navigateToSecondSheet(parentFragmentManager)
}
}
navigateToSecondSheet(fm: FragmentManager) {
SecondSheet.show(fm)
}
Second Bottom Sheet:
companion object {
fun show(fm: FragmentManager) {
SecondSheet().show(fm, "TagA")
}
}
So how can I get the first bottom sheet to always be dismissed?
maybe use:
dismissAllowingStateLoss()
Related
I want an alert dialog to be shown, when an user scrolls from one page to the other inside a ViewPager2. I know about OnPageChangeCallback interface, but cannot figure out how to use it.
class showAlert() : Fragment(){
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
binding?.ViewPager?.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){
override fun onPageScrollStateChanged(state: Int) {
createAlert()
}
})
}
...
private fun createAlert() : Dialog {
return AlertDialog.Builder(childFragmentManager)
.setTitle("Exit?")
.setMessage("If you leave, then the data will be lost")
.setNegativeButton(android.R.string.VideoView_error_text_unknown, new onClickListener())
}
...
}
Again, the whole point is, when the user scrolls from one fragment to another inside the viewpager, an alert dialog should be shown, asking it whether it wants to move to another fragment or not.
I'm using following approach to create bottomsheet dialog, dialog is creating but I want to dismiss on backpress for that all setup I'm using the code below. But not doing able to dismiss dialog.
class MainActivity : BaseClass(), View.OnClickListener {
private lateinit var bottomSheetDialog: BottomSheetDialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomSheetDialog=BottomSheetDialog(this)
create.setOnClickListener {
createBottomSheetDialog()
}
}
override fun onBackPressed() {
if (bottomSheetDialog.isShowing){
bottomSheetDialog.dismiss()
}
super.onBackPressed()
}
private fun createBottomSheetDialog(){
bottomSheetDialog.setContentView(R.layout.bottom_sheet_dialog)
bottomSheetDialog.setCancelable(false)
bottomSheetDialog.show()
}
}
I have been tried using this.bottomSheetDialog.dismiss()
but not working I also have try dismissing the dialog without if statement and without using super.onBackPressed() but not working.
you can simply remove this line from your code
bottomSheetDialog.setCancelable(false)
You can get more details about this here. I guess you need to stop dismiss when clicked anywhere outside the fragment so you can add this :-
bottomSheetDialog.setCanceledOnTouchOutside(false)
It will allow you to dismiss onBackPressed but it won't allow you to dismiss if clicked anywhere outside of your bottom sheet.
Also no need to write this in your Main activity :-
override fun onBackPressed() {
if (bottomSheetDialog.isShowing){
bottomSheetDialog.dismiss()
}
super.onBackPressed()
}
Bottom Sheet dialogue will itself dismiss onBackPressed.
Try this:
override fun onBackPressed() {
if (bottomSheetDialog.isShowing){
bottomSheetDialog.dismiss()
} else {
super.onBackPressed()
}
}
Try setting global variable for activity dialog: BottomSheetDialog? = null
Then in the function for displaying dialog give it a value and show it. Then in onCreate (or whenever you want) just use global variable as a reference eg.:
onBackPressed(){
if(dialog != null){
dialog.dismiss()}}
edit: 2020.4.12 correct typo from Button.performClick() to button.performClick()
I am writing an app which should display a splash page/fragment for a
few seconds at start then display the next fragment in the navgraph. There are seven fragments in the navgraph which I can navigate around those fragments just fine.
The issue is with the splash fragment, I can only get the splash fragment to display/inflate when the button.onClickListener is set to accept a manual user
input -> click. (vs using button.performClick())
The desired end result is to display a fragment layout consisting of an image view and a text view for a few seconds at app start before displaying the next fragment layout in the navgraph, without having the user to click or press anything.
I have tried using threadsleep, a runnable with a handler, and even a while loop with performClick(). None of which have yielded acceptable results. The closest I have come to getting the desired result is the following:
class SplashFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater,
rootContainer: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflater(R.layout.fragment_splash, rootContainer, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
button.setOnClickListener {
updateABode()
}
// pizzaLoop initialized to give about 4 seconds delay
val pizzaLoop = 1500000000
while (pizzaLoop > 0) {
pizzaLoop--
if (pizzaLoop == 0) {
button.performClick()
}
}
private fun updateABode {
val ABode = "A" // hard coded for testing purposes
when (ABode) {
"B" -> // for testing purposes only -- does nothing
"A" -> findNavController().navigate(R.id.action_splashFragment_to_firmwareFragment)
}
}
}
With the pizzaLoop installed, the splash fragment will not inflate, but I do see the delay via the firmware screen update. (intially all I get is a white blank screen then subsequent calls to the SplashFragment class show nothing but the firmwareFragment screen (next in the navgraph) -- and the pizzaLoop delay is noticable).
When I comment out the pizzaLoop then the splash fragment displays as intended but I have to click the button to bring up the next fragment in the navgraph (the rest of the navgraph works fine).
It's like the button.performClick() method is preventing the inflation of the splash fragment.
EDIT: 2020.4.12 TO PROPERLY POST SOLUTION.
class SplashFragment : Fragment() {
private val handler: Handler = Handler()
private val updateRunnable: Runnable = Runnable { updateABode() }
override fun onCreateView(inflater: LayoutInflater,
rootContainer: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflater(R.layout.fragment_splash, rootContainer, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
button.setOnClickListener {
handler.removeCallbacks(updateRunnable)
}
handler.postDelayed(updateRunnable, 4000)
}
private fun updateABode {
val ABode = "A" // hard coded for testing purposes
when (ABode) {
"B" -> // for testing purposes only -- does nothing
"A" -> findNavController().navigate(R.id.action_splashFragment_to_firmwareFragment)
}
}
}
Got a class that extends BottomSheetDialogFragment
When I set the dialog to show, the slide from bottom animation occurs and the dialog is shown. Now, If I set the app to background and then bring it back to the foreground, the dialog that was already showing does the same slide in animation.
How can I disable this, that is, if the dialog is already showing, sending the app to background and then foreground does not start the animation?
Showing the dialog like this:
dialog = MyDialogFragment()
dialog?.run {
val args = Bundle()
....
arguments = args
show(this#MyFragment.fragmentManager, tag)
}
Where the dialog class only has this:
class MyDialogFragment : BottomSheetDialogFragment() {
var listener: Listener? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// inflate view
// Given the arguments, sets up the ui
return view
}
interface Listener {
...
}
}
And that's all the code that I have for the dialog.
Combining #nntk and #CKotlin answers made the trick for me. I manage to fix the issue with this code :
override fun onStop() {
super.onStop()
dialog?.window?.setWindowAnimations(-1)
}
Edit:
On Android < P (API 28), it makes the app not responding to touch events. So either you don't use it or you need to surround it with a check:
override fun onStop() {
super.onStop()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
dialog?.window?.setWindowAnimations(-1)
}
}
overwrite onStop() method in BottomSheetDialogFragment
such as
#Override
public void onStop() {
super.onStop();
getDialog().show(); // important
}
I'm dealing with the same issue. I haven't fully been able to solve this, but I was able to stop the slide up animation from occurring on resume by doing the following:
override fun onResume() {
super.onResume()
// Disable dialog window animations for this instance
dialog?.window?.setWindowAnimations(-1)
}
This doesn't stop the background fade from animating though, so the background shade shows, disappears, and then shows again.
My bottomSheet behaves correctly except in this situation. When I return to the activity via 'back button', I want the bottomSheet to collapse and I thought the code below would do the trick, but it doesn't work. What could be the cause ? (I confirmed with debugger that it reaches the statement)
#Override
public void onBackPressed() {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
the same line works fine when it returns via finish():
if (resultCode == Activity.RESULT_OK) {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
If your dialog has setCancelable(true), back button will not trigger the onbackpressed(), you can try this
I have a class call BottomSheetFragmentDialog which is extend from BottomSheetDialogFragment and I have setCanceledOnTouchOutside(false) inside the onCreateDialog Method also overrdie the onCancel()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.setCanceledOnTouchOutside(false)
return dialog
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
Toast.makeText(context, "Break Point Here", Toast.LENGTH_SHORT).show()
}
you can use this code onBackPressed() methode
behavior.setState(BottomSheetBehavior.STATE_HIDDEN);
Simpler solution.
Don't have to override onBackPressed method, just have to remove setCancelable(true) and add bottomSheetDialog.setCanceledOnTouchOutside(false) when you initialise the bottomSheetDialog.