I'm currently adding a new fragment (using single activity pattern) to my supportFragmentManager via add() method from another fragment. But my new fragment uses only half of the screen, and I still can interact with the fragment in background. Is there any way to block user interaction with background fragment? Just like DialogFragment do. Also, I cant use dialog fragments cause of this.
Well, right after posting a question i looked up in DialogFragment code and found in onStart() method this lines:
View decorView = mDialog.getWindow().getDecorView();
ViewTreeLifecycleOwner.set(decorView, this);
ViewTreeViewModelStoreOwner.set(decorView, this);
ViewTreeSavedStateRegistryOwner.set(decorView, this);
To make it work in regular fragment i just edited first line to this
val view = myRootView as View //View decorView = mDialog.getWindow().getDecorView();
And that's it
You can use dialog fragment for half of screen (Did you use material dialog fragment).
https://medium.com/#kosta.palash/using-bottomsheetdialogfragment-with-material-design-guideline-f9814c39b9fc
And you can use Eventbus(https://github.com/greenrobot/EventBus) or SingleEvent (https://abhiappmobiledeveloper.medium.com/android-singleliveevent-of-livedata-for-ui-event-35d0c58512da#:~:text=LiveData%20notifies%20Observer%20objects%20when,every%20time%20there's%20a%20change.) for notify the background fragment
Related
When I open an dialog and navigate the screen from A Fragment to B Fragment,
The dialog is still shown above B Fragment.
I do dismiss & null to the dialog fragment property. But still, sometimes, it exists.
So, What I do is, calling this in B Fragment. (In this case, Bottom Sheet)
(requireActivity().supportFragmentManager).findFragmentByTag(MyBottomSheet.TAG)?.let {
if(it is MyBottomSheet) {
it.dismiss()
}
}
This is better, but it doesn't work sometimes too. So, I thought this is because screen animation. So, I gave 200L before calling dismiss(). Then, It seems to work better.
However, I don't think this is the true and complete solution.
How can I restrict a dialog to a fragment so that I don't need to consider those dismiss thing here and there.
When I create DialogFragment or BottomSheet. I set attachToParent = true like this.
_binding = DataBindingUtil.inflate(inflater, R.layout.modal_bottom_sheet_my, container, true)
And also when I navigate between fragments, I launch it singleTop.
But none of them worked. How can I solve this questioin? Is there something like single instance?
Hello i create class that implement BottomSheetDialogFragment with dynamic content. The content is a Fragment. So when initialize the BottomSheet i passing fragment object, and attach it to specific Container ID inside this BottomSheetDialogFragment. Looks like this :
private fun attachContentFragment() {
val transaction = childFragmentManager.beginTransaction()
transaction.apply {
replace(R.id.flContent, state.layoutContent)
commit()
}
}
state.layoutContent is my attached Fragment
I need to dismiss the BottomSheet if every action called in that fragment.
As far as i know, i need to get the object of BottomSheet that hold me(Fragment) and dismiss it.
But how i can get that BottomSheet object?
Thanks
So, technically it is a fragment inside fragment situation. I think there is several solutions here:
Call Activity from your child fragment. BottomSheetDialogFragment will subscribe to Activity for such events and react on them.
Get the instance of a BottomSheetDialogFragment by calling proper FragmentManager (which possible is an Activity one). You can get an instance of a fragment byTag for example.
Or you can call getParentFragment from a child Fragment.
I want to pop up a timepicker and a datepicker, more than once in an Activity.
It's not clear to me whether I should make one instance of each, and show them as needed, or if I should make new instances each time I need to pop a dialog up.
And I'm very confused by findFragmentByTag/findFragmentById. It seems that the fragment is only found if it's currently displayed?
But if it's not found and I make a new Fragment and show it with the same tag, I get an IllegalStateException. How can I recover a fragment in onCreate?
Currently, I'm doing this:
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState == null) {
timePicker = new RadialTimePickerDialog();
datePicker = new CalendarDatePickerDialog();
fm.beginTransaction().add(timePicker, FRAGMENT_TIME_PICKER)
.add(datePicker, FRAGMENT_DATE_PICKER).commit();
} else {
timePicker = (RadialTimePickerDialog)
fm.findFragmentByTag(MedicationCollapsePanel.FRAGMENT_TIME_PICKER);
datePicker = (CalendarDatePickerDialog)
fm.findFragmentByTag(MedicationCollapsePanel.FRAGMENT_DATE_PICKER);
}
As I mentioned, this fails to actually find the fragments, and almost as bad, it displays them immediately when the Activity starts, which I don't want.
Thanks.
I assume these classes are the ones by the same name from gitHub that pop up at the top of a google search.
They extend dialogFragments.
DialogFragments take care of removing themselves with the fragment manager when they are dismissed. You can see the source code as well as get this decription, from the link below:
Dismiss():
Dismiss the fragment and its dialog. If the fragment was added to the
back stack, all back stack state up to and including this entry will
be popped. Otherwise, a new transaction will be committed to remove
the fragment.
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/app/DialogFragment.java#DialogFragment.onDismiss%28android.content.DialogInterface%29
Hence, they are not reusable after being dismissed since they will unattach themselves automatically by calling the underlying context and getting the fragment manager themselves. Rather create a new instance, and show them, or you can try overriding their default behavior. You can try either changing what they do after being dismissed, or prevent them from being dismissed in the first place (e.g. hiding them).
I have a DialogFragment that I launch when a user taps a menu item on the ActionBar. Everything about the Dialog functions properly - it launches just fine and it does everything I've set it up to do. Unfortunately, as soon as I rotate my device, the DialogFragment disappears.
This seemed to be a common problem back in 2012 - I've scoured StackOverflow and tried all of the common fixes that have been posted in the last couple of years. This SO post in particular summarizes all of the potential fixes that have been proposed:
Set up the DialogFragment to use the newInstance() paradigm
Add setRetainInstance(true) to the DialogFragment's onCreate()
Add a workaround to onDestroyView() to address a potential bug in the support library
Despite implementing everything above, the DialogFragment refuses to stick around after device rotation.
Here's how I launch the DialogFragment from the Activity:
DialogKanjiLookup dialog = DialogKanjiLookup.newInstance(gSearchView.getQuery());
dialog.show(getSupportFragmentManager(), "dialogKanjiLookup");
Here is the DialogFragment's newInstance():
public DialogKanjiLookup() {}
public static DialogKanjiLookup newInstance(CharSequence searchTerm)
{
DialogKanjiLookup dialog = new DialogKanjiLookup();
Bundle args = new Bundle();
args.putCharSequence(BUNDLE_SEARCH, searchTerm);
dialog.setArguments(args);
return dialog;
}
Here's the dialog's `onCreateDialog():
#Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
// Specify a layout for the dialog
LayoutInflater inflater = getActivity().getLayoutInflater();
View layout = inflater.inflate(R.layout.dialog_kanjilookup, null);
// SNIP
// ...Handle savedInstanceState, set up various Listeners and adapters...
// SNIP
// Create the actual dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Customize the dialog
builder.setTitle(R.string.dialog_kanji_lookup_title);
builder.setIcon(R.drawable.kanji_lookup);
builder.setPositiveButton(R.string.menu_search, btnSearchListener);
builder.setNegativeButton(R.string.cancel, null);
builder.setView(layout);
// Force the dialog to take up as much space as it can
Dialog dialog = builder.create();
dialog.show();
dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
// Display the dialog
return dialog;
}
There's only one instance of DialogFragment.dismiss() called from within the fragment but that's only triggered when the user taps one of the dialog's buttons, so I've ruled that out. Why does my DialogFragment still disappear after rotation? I'm all but pulling my hair out over this, it worked fine until sometime after I implemented a Navigation Drawer. Could that be a part of the problem?
EDIT: False alarm, I discovered that my answer wasn't the solution! The problem reappeared after I finished moving all of my Fragments and Activities away from using the Support Libraries.
I did discover that this problem only exists in Activities in which the content fragment has not been declared statically in the Activity's layout. That is, if I have a <FrameLayout> defined in XML and use fragmentManager.beginTransaction().replace(R.id.content_frame, frag, tag).commit(); to load a fragment, any DialogFragments launched in that activity fail to reload when the device has been rotated.
Here's a screen recording that demonstrates the issue:
https://www.youtube.com/watch?v=psK0pzMn6oc
After some experimentation I discovered a solution. The Activity that launches the dialog needs to extend android.support.v4.app.FragmentActivity, and the DialogFragment needs to extend android.support.v4.app.DialogFragment.
Then, getSupportFragmentManager() must be called when launching the DialogFragment:
CustomDialog dialog = CustomDialog.newInstance();
dialog.show(getSupportFragmentManager(), "customDialog");
This should retain the dialog during rotation. There was no need to use setRetainInstance(true) in the dialog itself.
Mind you, this only works in instances in which an FragmentActivity calls a DialogFragment. I'm still trying to suss out a way to preserve a dialog that gets called via a Fragment instead.
i have a piece of code where i wish to just hide the current fragment so it doesnt destroy its view and then show a new one using this :
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.hide(oldFragment);
ft.show(newFragment);
ft.commit();
The issue is that when i execute the above code, it doesnt show any UI components.
if i do ft.replace(id,fragment); it works but i do not want to remove the previous displayed fragment as i want to maintain the fragments and its views so i dont need to re-initialise it
Did you previously add newFragment to some part of your Activity's view hierarchy? If you just instantiate a Fragment and tell it to show, it won't know where to show (unless it's a DialogFragment, I guess). You need to use add(somelayoutid,fragment,"sometag") for each Fragment and then you can hide/show them as you'd like. You can also just continually use replace, rather than hide/show, if you don't need to keep your Fragment's around while they're hidden.
"sometag" will be useful if you're handling rotation so you can retrieve a reference to each Fragment after your Activity is recreated, and then you can hide/show them as before.
Was your fragment initialized before calling this?
if (newFragment == null) {
// If not, instantiate and add it to the activity
ft.add(yourFragmentContainerId, newFragment,"tag");
} else {
// If it exists, simply attach it in order to show it
ft.show(newFragment);
}