I have created a custom compound view by extending FrameLayout. That view can be on a dialogue box (among others). But what if I want to do some clean-up work when the view disappears from the screen, such as the user's closing the dialogue box? Can I get some kind of onDestroy event? Or should I make the owner (such as the dialogue box or the fragment) call the view's clean-up method on its (owner's) onDestroy or dismissed event?
try to use
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
Related
I need to show a preference dialog that wait for Joypad keypress.
I know that DialogFragment has its own Window then has its own onKeyListener.
I can easily catch Joypad press by setting a listener like that.
public class MyDialogFragment extends PreferenceDialogFragmentCompat {
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
builder.setOnKeyListener(new DialogInterface.OnKeyListener() {
#Override
public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) {
// do stuff with intercepted key press
return true;
}
});
}
}
But, I have trouble catching GenericMotionEvents. In order to intercept them, I've overridden onGenericMotionEvents in the Activity class and eventually forward the Event by calling a method on MyDialogFragment class.
It works 100% correctly when MyDialogFragment is not shown as when an analog trigger/direction stick is moved, I can get an event.
The weird part is that IF MyDialogFragment is shown, then I can get only analog direction stick events BUT NOT left/right analog triggers events.
Does someone know why and how to fix this behaviuor?
I've had a similar issue some time ago. You can use onGenericMotionEvent of Dialog or even some of the Views. It has some limitations though and works not as expected sometimes. It does work as intended though - it is just that sometimes all the generic motion events are being intercepted by something else and they aren't propagated any further anywhere - in this situation, you won't receive the callback trigger.
That is what was happening in my case and even overriding the callback method in Dialog(I haven't tried View though) failed to give me the needed result. What I did is a bit of a kludgy trick, but it did the job. I created my activity's UI as a child of one parent FrameLayout and my dialog UI was the topmost element in this FrameLayout. This trick allowed me to use the activity's native onGenericMotionEvent callback. It added some navigation handling overhead and was generally possible because of allowing UI design(without dialog shadow etc) but yeah...
Maybe some of these approaches will help you.
So this has been bothering me for the past couple of hours.
I have a dialog which extends, you guessed it, Dialog. I do not want to close the dialog when the user click outside of the dialog. That's rather easy, since I can simply use this line: dialog.setCanceledOnTouchOutside(false). However, I do want to perform certain actions when the user touches outside of the dialog. That the dialog does not close is easy too (How to cancel an Dialog themed like Activity when touched outside the window?):
getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);
getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
And then implementing a custom onTouchEvent(MotionEvent event).
However, this does not only not dismiss the dialog, but also performs actions to underlying, say, buttons and such. I've tried some of the other potential answers (empty, false returning onTouchListener on root view, checking whether or not a touch was inside the dialog, etc.) in the post as well, but to no avail.
Now my question is: How can I create a Dialog that does not close on outside click, nor does it perform actions on buttons and such on the underlying layout/activity, but does inform me/catches an event when the user clicks outside the dialog?
I would rather use DialogFragment with custom layout. In layout create viewgroup that will fill UI and will be transparent (that layout will catch outside clicks). Put your dialog inside this layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/background"
android:gravity="center"
android:background="#color/transparent">
...
</LinearLayout>
Then in onCreateView:
View view = inflater.inflate(R.layout.popup_exit, container, false);
LinearLayout background = (LinearLayout) view.findViewById(R.id.background);
background.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("ExitDialogFragment", "onBackground click");
}
});
and onCreate:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Translucent_NoTitleBar);
}
Tested it and it works.
I use this code to make a screenshot. However, when I try to call it from the dialog (once user clicked the neutral button or when dialog.show() is called) - the dialog itself is not captured. When (or where) should I use this code to capture the dialog also?
Maybe extending Dialog and override onAttachedToWindow method to call your screenshot method from there would work. Something like this.-
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
takeScreenshot();
}
The code you are using uses drawing of root View to bitmap. Dialogs, Toasts and other extra windows have different View roots, therefore they do not appear in the screenshot.
Try out this library: https://github.com/jraska/Falcon it can solve your problem.
I want to be able to block all UI interaction with a fragment until a callback occurs.
I have two buttons: ButtonA and ButtonB.
ButtonA shows a progress bar and kicks-off an asynchronous thread that calls-back to the fragment when it's done. In the meantime, someone can press ButtonB which I don't want to allow.
My solution was to spin up another fragment which is transparent and intercepts all clicks. However there appears to be delay between FragmentManagers commit() and the fragment actually working.
I've tried calling executePendingTransactions() but I still end up with threading issues whereby the fragment isn't in a state to accept onClick events before the user hits ButtonB.
Is there a more elegant solution?
Thanks,
John
Another option is to use a progress dialog fragment and set it to be non cancelable. It will cover the fragment and prevent the underlying fragment from receiving any touch event.
Instead of calling another fragment,u can have another tranparent view with a progress dialog above the present view and make its visibility VIEW or GONE accordingly.Else u can simply show a prgress dialog with cancelable parameter as false.
Call buttonB.setEnabled(false); after clicking buttonA.
CustomButton extends View {
private boolean mIsEnabled = true;
public void setEnabled (boolean enabled) {
this.mIsEnabled = enabled;
}
#Override
public void onClick() {
if (mIsEnabled) {
mOnClickListener.onClick();
} else {
return;
}
}
}
I didnt understood the question perfectly..
hope it may helps you.
when you adding transaprent fragment over it make the transparent layout clickable=true
if a view is mentioned as clickable it does not pass touch events to below views.
sorry if i understtod your question wrong.
Can't button A put its containing activity in a given state (with a boolean flag raised in its listener) and button B read that flag before doing any stuff ?
I think it's not only a UI issue here but also some presentation logic and mini-state machine that you should implement. This mechanism plus the fragment you already have should be enough to prevent gaps in the sequence of executions of UI Thread events.
I started using DialogFragment, because they are working nicely through orientation changes, and stuff. But there is nasty problem I encountered.
I have AsyncTask that shows progress DialogFragment and dismisses it onPostExecute. Everything works fine, except when onPostExecute happens while application is in background (after pressing Home button, for example). Then I got this error on DialogFragment dismissing - "Can not perform this action after onSaveInstanceState". Doh. Regular dialogs works just fine. But not FragmentDialog.
So I wonder, what is the proper way of dismissing DialogFragment while application is in background? I haven't really worked with Fragments a lot, so I think that I'm just missing something.
DialogFragment has a method called dismissAllowingStateLoss()
This is what I did (df == dialogFragment):
Make sure that you call the dialog this way:
df.show(getFragmentManager(), "DialogFragment_FLAG");
When you want to dismis the dialog make this check:
if (df.isResumed()){
df.dismiss();
}
return;
Make sure that you have the following in the onResume() method of your fragment (not df)
#Override
public void onResume(){
Fragment f = getFragmentManager().findFragmentByTag("DialogFragment_FLAG");
if (f != null) {
DialogFragment df = (DialogFragment) f;
df.dismiss();
}
super.onResume();
}
This way, the dialog will be dismissed if it's visible.. if not visible the dialog is going to be dismisded next the fragment becomes visible (onResume)...
This is what I had to do to achieve what you want:
I have a Fragment activity on which i was showing a dialog fragment named fragment_RedemptionPayment which is globally declared at the top. The following code dismisses the DialogFragment if it was showing before the activity goes in background and comes back in foreground.
#Override
public void onResume() {
super.onResume();
if(fragment_RedemptionPayment.isVisible()){
fragment_RedemptionPayment.dismiss();
}
}
Another new way of checking the state before calling dismiss is this:
if(!dialog.isStateSaved){
dialog.dismiss()
} else {
//Change the UI to suit your functionality
}
In this way its is checked that state is saved or not, basically on pause and onSaveInstanceState has been called.
For Java you can use isStateSaved()
A solution that might work is setting Fragment.setRetainInstance(true) in your dialogfragment, but that's not the prettiest of fixes.
Sometimes I have noticed that I have to queue up my dialog actions to let the framework restore the state first. If you can get hold of the current Looper (Activity.getMainLooper()) and wrap that in a Handler you could try passing your dismissal to the back of the queue by posting a runnable on that queue.
I often end up using a separate fragment that it retaininstance(true) that has a ResultReceiver. So i pass on that result receiver to my jobs and handle callbacks in its onReceive (often as a router for other receivers). But that might be a bit more work than it is worth if you are using async tasks.