Android dialog has no focus - android

I have a problem about Android dialog, most of the issues appears on Samsung devices, I'm not sure whether other devices have the same problem.
When a dialog(AlertDialog or DialogFragment) is shown, it has no focus and I can't click at anything on the dialog. It seems that focus is still on activity or fragment who creates the dialog, the activity/fragment below the dialog has response to my touch events.
I use this to create a AlertDialog
new AlertDialog.Builder(activity)
.setTitle(R.string.about_title)
.setMessage(buildAppInfo())
.setNegativeButton(R.string.app_ok, (dialog, which) -> dialog.dismiss())
.show());
This is my DialogFragment class:
public class MyDialog extends DialogFragment {
private MyDialogBinding binding;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.my_dialog, container, false);
binding.tvTitle.setText(R.string.dialog_title);
binding.tvMessage.setText(R.string.dialog_content);
binding.btnCancel.setOnClickListener(v -> dismiss());
return binding.getRoot();
}
#Override
public void show(#NonNull FragmentManager manager, String tag) {
if (!isAdded() && null == manager.findFragmentByTag(tag)) {
super.show(manager, tag);
}
}
}
And use this to create a DialogFragment
private final MyDialog dialog = new MyDialog();
dialog.show(getChildFragmentManager(), "");
Function setCancelableOnTouchOutside does not work. This issue occurs sometimes, when it occurs, I have to restart my app. Thank you very much in advance for your help.

Related

How to block the click event to the background of DialogFragment around Samsung S9 Edge button

I have a UI requirement showing a blocking DialogFragment, which can not be dismissed by clicking on the background.
Also when the DialogFragment is showing, any view under it cannot be clicked.
Things are working well except on the Samsung S9 device.
On Samsung S9, which has an edge button, when clicking around the edge button's edge, the view under the DialogFragment got clicked and the event performed, which is not as expected.
Here is a sample code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyDialogFragment myDialogFragment = new MyDialogFragment();
myDialogFragment.show(getSupportFragmentManager(), MyDialogFragment.TAG);
}
});
findViewById(R.id.background).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("wrong", "clicked!!!!---------------");
Toast.makeText(MainActivity.this, "Click!", Toast.LENGTH_LONG).show();
}
});
}
}
The layout is quite simple, just a LinearLayout with a button inside it.
Clicking button will show the blocking dialog.
The LinearLayout id is background, which should not be clicked after the dialog has shown.
The dialog code:
public class MyDialogFragment extends DialogFragment {
public static final String TAG = "Dialog";
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setCancelable(false);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.my_dialog_layout, container, false);
getDialog().setCanceledOnTouchOutside(false);
return view;
}
#Override
public void onResume() {
Window window = getDialog().getWindow();
Point size = new Point();
Display display = window.getWindowManager().getDefaultDisplay();
display.getSize(size);
window.setLayout((int) (size.x * 0.8), WindowManager.LayoutParams.WRAP_CONTENT);
window.setGravity(Gravity.CENTER);
super.onResume();
}
}
But now when the dialog is showing, click the area on the edge button, the background click listener can be entered, I can get the log and toast.
How to prevent this?
In the event that is firing I'd do
Fragment currentFrag = getSupportFragmentManager().findFragmentByTag(MyDialogFragment_TAG);
if (!(currentFrag instanceof MyDialogFragment))
{
// your code for when you're dialog fragment is not visible
}
setcancelable(false); can be used to block clicking on background till task completes
Give the root node an id
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/constraintlayoutRoot"
Add an empty OnClickListener
public View onCreateView(...) {
View view = _inflater.inflate(R.layout.fragment_xyz, _container, false);
view.findViewById(R.id.constraintlayoutRoot).setOnClickListener(view1 -> {
});

DialogFragment onCreateView not returning custom layout view?

I'm currently trying to use a custom layout with my DialogFragment, however it seems I'm doing something wrong. This is what my class currently looks like:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
setRetainInstance(true);
Log.d(TAG, "onCreateDialog");
return new AlertDialog.Builder(getActivity())
.setPositiveButton(android.R.string.ok, passDataListener)
.setNegativeButton(android.R.string.cancel, null)
.setCancelable(true)
.create();
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
setTitleFromBundle();
return inflater.inflate(R.layout.dialog_edittext, container);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mEditText = (EditText) view.findViewById(R.id.dialog_edittext);
tvUnits = (TextView) view.findViewById(R.id.dialog_units);
setMaxCharsFromBundle();
setTextFromBundle();
setHintFromBundle();
setInputTypeFromBundle();
setUnitsTextViewFromBundle();
}
The positive/negative buttons show (along with the title) however, my layout does not.
don't need to override onCreateView()
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
setRetainInstance(true);
Log.d(TAG, "onCreateDialog");
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return new AlertDialog.Builder(getActivity())
.setView(inflater.inflate(R.layout.dialog_edittext, null))
.setPositiveButton(android.R.string.ok, passDataListener)
.setNegativeButton(android.R.string.cancel, null)
.setCancelable(true)
.create();
}
You can't use both methods onCreateDialog and onCreateView at the same time. You have to choose if you want to show a "basic dialog" then overwrite onCreateDialog. If you want to show a "custom dialog" then overwrite onCreateView. Note that you can also overwrite onCreateDialog and set your own layout with youralertdialog.setView().
You should implement only one method between onCreateView and onCreateDialog, not both of them.
onCreateView : to supply the content of the dialog
onCreateDialog : to create an entirely custom dialog, such as an AlertDialog, with its own content
Everything is described in the documentation here
For a complete guide you can see https://guides.codepath.com/android/Using-DialogFragment

Fragment,DialogFragment Issue

I am calling dialog fragment from FragmentA and returning some values to fragmentA. Now issue is whenever i go to another fragmentB from same fragmentA and return to it my dialog fragment values get cleared.
when i click on consultant doctor textview, a dialog opens (Pic 2). On Selecting an item (Pic 2),returns a value back to FragmentA. Pic 3 is a Fragment B which opens on same activity. But when i click on cross button on pic 3 and popBackStack , my value for consult doctor clears shown in Pic 4.
Pic 4 is an ISSUE
DialogFragment
#Override
public void onStart() {
super.onStart();
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
getDialog().getWindow().setGravity(Gravity.CENTER);
getDialog().setCancelable(false);
getDialog().setCanceledOnTouchOutside(false);
getDialog().closeOptionsMenu();
}
#Override public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable #Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
View rootView = inflater.inflate(R.layout.consultant_doc_dialog, container, false);
recyclerView = (RecyclerView)rootView.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
adapter = new ConsultantDoctAdapter(getContext(),this);
adapter.getDocList().addAll(new ArrayList<DoctorList>());
recyclerView.setAdapter(adapter);
adapter.getDocList().clear();
adapter.getDocList().addAll(list);
adapter.notifyDataSetChanged();
close = (ImageButton)rootView.findViewById(R.id.bt_close);
close.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
getDialog().dismiss();
}
});
//cityEditText.setOnQueryTextListener(onQueryTextListener);
return rootView;
}
Fragment
#Nullable #Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_create_leads, container, false);
ButterKnife.bind(this, view);
setRetainInstance(true);
init();
setPicker();
setSpinnerListener();
btCheckCalendar.setOnClickListener(this);
etCityId.setOnClickListener(this);
etConsultingDocId.setOnClickListener(this);
btSubmit.setOnClickListener(this);
tvClientReferral.setOnClickListener(this);
etSalesPerson.setText(sharedPref.getString(AppConstants.PREFERENCE_USER_NAME, ""));
etZone.setText(sharedPref.getString(AppConstants.USER_ZONE, ""));
etAreaCode.setText(sharedPref.getString(AppConstants.USER_AREA_CODE, ""));
setSpinner();
getConsultantDoctorList();
return view;
}
Fragment B callBack:
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_main, new MyCalendarFragment())
.addToBackStack("calendarFragment")
.commit();
DialogCallack:
ConsultantDocDialogFragment consultantDocDialog = new ConsultantDocDialogFragment();
consultantDocDialog.setParameter(getContext(), this, doclist);
consultantDocDialog.show(getActivity().getSupportFragmentManager(),
ConsultantDocDialogFragment.class.getSimpleName());
break;
Please help me so that i can able to save state of values got from dialog fragment.
Please find the following code it may help you-
This is Fragment Code where you can get CallBack from Dialog Fragment-
HomeFragment.java
public class HomeFragment extends Fragment implements AlertDFragment.Callback {
private static final int DIALOG_FRAGMENT = 100;
Button alertdfragbutton;
private View rootView;
public HomeFragment() {
}
public static HomeFragment newInstance() {
return new HomeFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_home, container, false);
initUI(rootView);
return rootView;
}
private void initUI(View rootView) {
alertdfragbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
AlertDFragment alertdFragment = new AlertDFragment();
alertdFragment.setTargetFragment(HomeFragment.this, DIALOG_FRAGMENT);
// Show Alert DialogFragment
alertdFragment.show(getChildFragmentManager(), "Alert Dialog Fragment");
}
});
}
#Override
public void accept() {
Log.e("Home ", "OK");
}
#Override
public void decline() {
}
#Override
public void cancel() {
Log.e("Home ", "CANCEL");
}
}
Here is Dialog Fragment where we declare CallBack with methods-
public class AlertDFragment extends DialogFragment {
Callback callback;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
callback = (Callback) getTargetFragment();
return new AlertDialog.Builder(getActivity())
// Set Dialog Icon
.setIcon(R.drawable.androidhappy)
// Set Dialog Title
.setTitle("Alert DialogFragment")
// Set Dialog Message
.setMessage("Alert DialogFragment Tutorial")
// Positive button
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
callback.accept();
// Do something else
//getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent());
}
})
// Negative Button
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
callback.cancel();
// Do something else
// getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, getActivity().getIntent());
}
}).create();
}
public static interface Callback {
public void accept();
public void decline();
public void cancel();
}
}
A simple way to return values from DialogFragment is using setTargetFragment for calling a fragmentB creation, then return data to getTargetFragment (if not null). In fragmentA you can receive data through onActivityResult.
Another way is using SharedPreferences. You can get a new value with onResume or onHiddenChanged.
Instead of using the "Fragment Transition" why don't you just POP-UP your custom view
Just Create a global reference of
Dialogue dialogue
View popupView
and on click of whatever textview button etc.
you can just call a method like
void popup(){
popupView = LayoutInflater.from(getActivity()).inflate(R.layout.your_calenderlayout, null);
//suppose you have TextView cal_textview in popUp view i.e, your_calenderlayout
cal_textview = (TextView ) popupView.findViewById(R.id.cal_textview);
dialog = new Dialog(getContext());
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCanceledOnTouchOutside(true);
dialog.setContentView(popupView); //and just add your popUpview
// For setting backgroung
/*dialog.getWindow().setBackgroundDrawableResource(android.R.color.Transparent);
*/
//For setting the width or height of popup
/*WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.CENTER;
dialog.getWindow().setAttributes(lp);*/
dialog.show();
}
and on dismiss of popUp or on click of the view inside popupView you set the value of variables or member inside the fragment directly
Hope this will help
You can use Shared prefs or sqlite to get your values and if you think its use less to save your temporary data in share prefs or sqlite Then Singleton model is a good option .. i believe we should follow KISS
design principle :P

How can I make a BottomSheetDialogFragment non-modal?

In onCreateView() I've tried setting some properties, but the DialogFragment still goes away on tapping outside.
I would like the fragment to remain nearly all the time while the user interacts with other parts of the app.
This is in a class that extends BottomSheetDialogFragment:
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
// makes background non-interactive
getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
// prevents dimming of background
getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
// no effect?
getDialog().setCanceledOnTouchOutside(false);
this.setCancelable(false);
return view;
}
Code like:
public class MyDialogFragment extends DialogFragment {
...
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(...)
.setMessage(...)
.setCancelable(false);
...
Dialog dialog = builder.create();
dialog.getWindow();
return dialog;
}
...
}
works for me.

Exception when showing a dialog after orientation change

I have an activity and a fragment inside it.inside fragment, there is a button, and on click of button a dialog shows.
Everything works, until user do a orientation change and click button after it.
IllegalStateException(cannot perform this action after onsaveinstancestate) occurs when user clicks button after orientation change. I'm using android support framework.
Anybody have any idea regarfing this?
Activity Code
public void openMoreDialog(String shareData, String link) {
DialogFragment dialog = new MoreDialog(shareData, link);
dialog.show(getSupportFragmentManager(), "MoreDialog");
}
Fragment Code
public void onAttach(Activity activity) {
super.onAttach(activity);
mControl = (ActivityControl)activity;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
ImageButton moreButton = (ImageButton)v.findViewById(R.id.moreButton);
moreButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mControl.openMoreDialog(shareData, link);
}
});
return rootView;
}
FragmentDialog code
public class MoreDialog extends DialogFragment {
private String mShareData;
private String mLink;
public MoreDialog(String shareData, String link){
mShareData = shareData;
mLink = link;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.more_dialog, null);
Button openBtn = (Button)dialogView.findViewById(R.id.openBtn);
openBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openLink(mLink);
}
});
Button shareBtn = (Button)dialogView.findViewById(R.id.shareBtn);
shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shareNews(mShareData);
}
});
builder.setView(dialogView);
return builder.create();
}
private void openLink(String link){
}
private void shareNews(String data){
}
}
Helpful link & solution how to:
https://stackoverflow.com/a/17413324/619673 and btw, constructor in fragment must be empty! Documentation:
http://developer.android.com/reference/android/app/Fragment.html
public Fragment ()
Added in API level 11
Default constructor.
Every fragment must have an empty constructor, so
it can be instantiated when restoring its activity's state. It is
strongly recommended that subclasses do not have other constructors
with parameters, since these constructors will not be called when the
fragment is re-instantiated; instead, arguments can be supplied by the
caller with setArguments(Bundle) and later retrieved by the Fragment
with getArguments().
Applications should generally not implement a constructor. The first
place application code an run where the fragment is ready to be used
is in onAttach(Activity), the point where the fragment is actually
associated with its activity. Some applications may also want to
implement onInflate(Activity, AttributeSet, Bundle) to retrieve
attributes from a layout resource, though should take care here
because this happens for the fragment is attached to its activity.

Categories

Resources