I am using a DialogFragment, and while I have successfully set an image to close (i.e. dismiss) the dialog when pressed, I am having a hard time finding the way to dismiss the dialog when the user clicks anywhere outside it, just as it works with normal dialogs. I thought there would be some sort of
dialogFragment.setCanceledOnTouchOutside(true);
call, but I don't see that in the documentation.
Is this possible with DialogFragment at all? Or am I looking in the wrong places? I tried intercepting touch events in the 'parent' activity but apart from not getting any touch event, it didn't seem right to me.
DialogFragment.getDialog().setCanceledOnTouchOutside(true);
Must be called in onCreateView (as Apurv Gupta pointed out).
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
getDialog().setCanceledOnTouchOutside(true);
...
}
/** The system calls this only when creating the layout in a dialog. */
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// The only reason you might override this method when using onCreateView() is
// to modify any dialog characteristics. For example, the dialog includes a
// title by default, but your custom layout might not need it. So here you can
// remove the dialog title, but you must call the superclass to get the Dialog.
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
Lot of answers here but, the app crash when dialog opens.
Writing getDialog().setCanceledOnTouchOutside(true); inside onCreateView did not work and crashed my app.
(I am using AppCompatActivity as my BaseActivity and android.app.DialogFragment as my Fragment).
What works is either of the two following lines:
getDialog().setCanceledOnTouchOutside(true);
OR
this.getDialog().setCanceledOnTouchOutside(true);
inside onActivityCreated like
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//getDialog().getWindow().getAttributes().windowAnimations = R.style.DialogAnimationZoom;
//getDialog().getWindow().setDimAmount(0.85f);
getDialog().setCanceledOnTouchOutside(true);//See here is the code
}
What not to use:
DialogFragment.getDialog().setCanceledOnTouchOutside(false);
throws following error
And writing the code in onCreateView crashes the App!
Please update the answer if you find something wrong.
If you want to execute some logic when clicking outside of a DialogFragment, just override the onCancel method.
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
// Do your work here
}
This works fine for Java:
DialogFragment.getDialog().setCanceledOnTouchOutside(false);
I would recommend to use my solution only after trying out above solutions. I have described my solution here. Just to brief, I am checking touch bounds of DialogFragment.getView(). When touch points are outside DialogFragment, I am dismissing the Dialog.
Dialog.SetCanceledOnTouchOutside(true);
Worked for me
My Code
class dlgRegister : DialogFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
....
....
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
Dialog.Window.RequestFeature(WindowFeatures.NoTitle);
Dialog.SetCanceledOnTouchOutside(true);
base.OnActivityCreated(savedInstanceState);
Dialog.Window.Attributes.WindowAnimations = Resource.Style.dialog_animation;
}
}
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup
container, #Nullable Bundle savedInstanceState)
{
DialogConfermationdialogBinding binding = DialogConfermationdialogBinding.inflate(inflater,container,false);
View view = binding.getRoot();
getDialog().setCanceledOnTouchOutside(false);
return view;
}
Related
I have an Android Activity, from which I want to show a Dialog. It would probably be a custom DialogFragment. Now when the user clicks on specific buttons I want the layout's inside the dialog to change with the data from the previous DialogFragment and so that it would have an ability to also go back to previous Layout.
I dont think there is an easy way to change views inside of the same DialogFragment so what would be the best way to do this?
I have tried doing it in method onViewCreated and when a button is clicked, but nothing happens.
In my activity I call the fragment like this at the moment:
FragmentManager fm = getSupportFragmentManager();
NewDialog newDialog = NewDialog.newInstace(userId, loc, currentId);
newDialog.setNewClickListener(new NewDialog.OnNewClickListener() {
#Override
public void onCancelClicked() {
finishAdd();
}
#Override
public void onAcceptClicked() {
...
}
});
newDialog.show(fm, "new_frag");
And the fragment:
public class NewDeliveryPointDialog extends DialogFragment {
private LayoutInflater inflater;
private ViewGroup container;
public NewDialog(){
}
public static NewDialog newInstace(){
...
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
this.inflater = inflater;
this.container = container;
return inflater.inflate(R.layout.dialog_layout_1, container);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
saveButton.setOnClickListener(v -> {
View.inflate(getContext(), R.layout.dialog_layout_2, container);
view.invalidate();
view.refreshDrawableState();
}
});
}
}
A DialogFragment is not made to have navigation to other fragments within the same dialog.
You basically have these options:
On your button click you close the Dialog and open another Dialog. But this seems odd. If there is so much happening, probably dialogs are not the best shot.
Instead of DialogFragments have another fragment container overlaying the original one (basically what a Dialog fragment does for you). Within the second container you can easily navigate to other fragments and set it to gone when the user finished interaction.
If there are just a few Views in the Dialog, you could consider setting the old ones to gone and the new ones to visible
I think your code didn't work, because container is null. Method onCreateView gives you #Nullable ViewGroup container, which is null for DialogFragment (but non null for Fragment). So when you call View.inflate(getContext(), R.layout.dialog_layout_2, container), it just creates a view in memory and doesn't attach it to container, cause it is null. See LayoutInflater.inflate, cause View.inflate is just a convenience wrapper for this function.
I dont think there is an easy way to change views inside of the same DialogFragment so what would be the best way to do this?
Instead of changing dialog root you can just manipulate child views inside dialog root layout (add, remove them, or change visibility).
Also my advice is to use recommended way to create dialog with custom layout (onCreateDialog + setView), but if you don't want to do that, you can refer view you've created in onCreateView as dialog root.
You can try creating a dialog fragment with an empty shell layout in which you would replace your two different fragments with ChildFragmentManager and regular fragment transactions
passing data between them can be done using the activity's view model since they both live in the same activity.
So add the ShellDialogFragment using the activity's FragmentManager and in the shell fragment class change between NewDialog & NewDeliveryPointDialog on your button click listener with ChildFragmentManager
I have a working DatePickerFragment that extends DialogFragment. I set up a DatePickerDialog in onCreateDialog() and then tried to add:
"picker.setCanceledOnTouchOutside(true);"
I am testing on a device with Android 8.0 Oreo and nothing happens when touching outside the DatePicker dialog. I am using androidx.appcompat.app.AppCompatActivity as my BaseActivity and androidx.fragment.app.DialogFragment for the DialogFragment;
Code:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onCreateDialog(savedInstanceState);
DatePickerDialog picker = new DatePickerDialog(getActivity(),this,year,month,day);
**picker.setCanceledOnTouchOutside(true);**
return picker;
This is the Activity code that creates the Fragment:
DatePickerFragment newFragment = new DatePickerFragment();
// tried the below also, with no luck
**newFragment.setCancelable(true);**
newFragment.show(getSupportFragmentManager(), "datePicker");
I also tried the below in the DialogFragment, also with no luck:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
getDialog().setCanceledOnTouchOutside(true);
...
}
and:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (getDialog() != null) {
getDialog().setCanceledOnTouchOutside(true);
}
return super.onCreateView(inflater, container, savedInstanceState);
}
I referenced this post for possible answers: How to dismiss a DialogFragment when pressing outside the dialog?. What am I missing here?
if you want to dismiss Dialog that extends DialogFragment, write
setCancelable(true);
inside onCreateView. The dialog will dismiss when you touching outside.
example code :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setCancelable(true);
return super.onCreateView(inflater, container, savedInstanceState);
}
did you try to set the dialog to cancelable
picker.setCancelable(true);
I thought I have similar problem, but it seems in my case that dialog has some shadow padding around it and I had to click outside of it very close to the edge of the screen to cancel it.
This is how i create my dialog:
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH)
val day = calendar.get(Calendar.DAY_OF_MONTH)
val dpd = context?.let {
DatePickerDialog(it, DatePickerDialog.OnDateSetListener { _, pickedYear, pickedMonth, pickedDay ->
//do something with picked date.
}, year, month, day)
}
dpd?.setCanceledOnTouchOutside(true)
dpd?.show()
Try to set setCanceledOnTouchOutside(true) in your implementation and try to dismiss it on tap very close to the edge of the screen, maybe test it on some big screen emulator like Pixel 3 XL. Now i know that this is not a solution and you need to handle all kind of devices and screen sizes, but I want you to verify that you might have same problem as me: that dialog will be canceled on touch outside, but this "outside" is not so obvious and it might be a real problem.
Just add setCancelable(true) in your Dialog onCreate method or in constructor
Try to use the default DatePickerDialog from android which is default close when selecting out side the dialog.
Try this is still issue let me know will send the proper code for same
I use Dialog Fragment I extend it
public class DocumentLibrarySelectionFragment extends DialogFragment
I am not sure how to dismiss this dialog when the user presses outside it (I show this dialog inside my activity). I went through other related questions, but couldn't find complete answer, for example this How to dismiss a DialogFragment when pressing outside the dialog? here, where to add this lines of code in the first answer? Thanks.
In onCreateView, you can add DialogFragment.getDialog().setCanceledOnTouchOutside(true);
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
getDialog().setCanceledOnTouchOutside(true);
...
}
I am working in an android application and am using a DialogFragment to show a dialog and I want to make that DialogFragment not cancelable. I have made the dialog cancelable property to false, but still its not affecting.
Please look into my code and suggest me a solution.
public class DialogTest extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return super.onCreateDialog(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_test, container, true);
getDialog().requestWindowFeature(STYLE_NO_TITLE);
getDialog().setCancelable(false);
return view;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_test, container, true);
getDialog().requestWindowFeature(STYLE_NO_TITLE);
getDialog().setCancelable(false);
return view;
}
instead of getDialog().setCancelable(false); you have to use directly setCancelable(false);
so the updated answer will be like this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_test, container, true);
getDialog().requestWindowFeature(STYLE_NO_TITLE);
setCancelable(false);
return view;
}
Use the following Snippet
void showDialog() {
DialogFragment newFragment = MyAlertDialogFragment.newInstance(
R.string..alert_dialog_two_buttons_title);
newFragment.setCancelable(false);
newFragment.show(getFragmentManager(), "dialog");
}
and if you want to disable the out side touch around dialog use the following line of code
DialogFragment.getDialog().setCanceledOnTouchOutside(true);
In case you use alert builder (and probably in every case you wrap dialog inside a DialogFragment) to help build your dialog, please don't use getDialog().setCancelable(false) or Dialog.setCancelable(false) because it's not going to work.
Use setCancelable(false) as shown in code below as it's mentioned in oficial android documentation:
public void setCancelable (boolean cancelable)
Added in API level 11
Control whether the shown Dialog is cancelable. Use this instead of directly calling Dialog.setCancelable(boolean), because DialogFragment needs to change its behavior based on this."
ref:http://developer.android.com/reference/android/app/DialogFragment.html#setCancelable(boolean)
public class MyDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_layout, null, false);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle("in case you want use a title").setView(view);
AlertDialog alert = builder.create();
// alert.setCancelable(false); <-- dont' use that instead use bellow approach
setCancelable(false); <- press back button not cancel dialog, this one works fine
alert.setCanceledOnTouchOutside(false); <- to cancel outside touch
return alert;
}
Simple Solution in DialogFragment
Used
dialog.setCanceledOnTouchOutside(false)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
AlertDialog.Builder(activity!!).apply {
isCancelable = false
setMessage("Your message")
// your other adjustments
return this.create()
}
}
worked for me.
The main thing is to use isCancelable = false over setCancellable(false)
within override fun onCreateDialog().
/**
* Control whether the shown Dialog is cancelable. Use this instead of
* directly calling {#link Dialog#setCancelable(boolean)
* Dialog.setCancelable(boolean)}, because DialogFragment needs to change
* its behavior based on this.
*
* #param cancelable If true, the dialog is cancelable. The default
* is true.
*/
DialogFragment.setCancelable(boolean cancelable) {
mCancelable = cancelable;
if (mDialog != null) mDialog.setCancelable(cancelable);
}
I have a dialog fragment using a custom layout with a quite complex View hierarchy. The code for the dialog fragment is more or less similar to the following.
public class CardDetailDialog extends DialogFragment {
public CardDetailDialog() {
setRetainInstance(true);
setStyle(STYLE_NORMAL, android.R.style.Theme_Light);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.card_detail_dialog, container, false);
/* Modify some view objects ... */
return view;
}
}
Whenever I invoked the show() method for this dialog fragment, I noticed that onCreateView is always called and layout inflation process is repeated. In my app, user might want to show the dialog multiple times during a session and I thought this is inefficient. Is there any way to keep the view / dialog instance across multiple show() invocation? Is it possible to do this using DialogFragment, or do I have to deal directly with Dialog class?
Using a boolean flag seems to do the trick (See the KEY CHANGEs). I override onCreateDialog, but employing the same strategy in onCreateView should work as well (keep a reference to your view you create)
I'm still getting some issues related to Orientation changes, but it may be related to a different issue
public class LogFragment extends DialogFragment{
private boolean isCreated; //KEY CHANGE
private Dialog mDialog; //KEY CHANGE -- to hold onto dialog instance across show()s
public LogFragment() {
setRetainInstance(true); // This keeps the fields across activity lifecycle
isCreated = false; // KEY CHANGE - we create the dialog/view the 1st time
}
#Override
public Dialog onCreateDialog(Bundle inState) {
if (isCreated) return mDialog; // KEY CHANGE - don't recreate, just send it back
View v = View.inflate(getActivity(),R.layout.log_layout,null);
mDialog = new AlertDialog.Builder(getActivity())
...
.create();
isCreated = true; // KEY CHANGE Set the FLAG
return mDialog;
}