I have a popup window in my activity.
Whenever I change the screen orientation to landscape, the popup disappears.
Why is that, and how can I keep the popup visible?
try below code:-
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
Log.i("orientation", "Orientation changed to: Landscape");
else
Log.i("orientation", "Orientation changed to: Portrait");
}
see below link for more info:-
How to keep Popup window opened when orientation changes at run time in Android?
When orientation changes the activity will restart.. So normally the popup window calls again.. In any case if it gone try to call it within onCreate.
Or check the orientation change and take necessary recalls.
if(getResources().getConfiguration().orientation == getResources()
.getConfiguration().ORIENTATION_LANDSCAPE){
// put some flag
}else if(getResources().getConfiguration().orientation != getResources()
.getConfiguration().ORIENTATION_PORTRAIT) {
// change the flag
}
If you put your code fragments may I can help you
You need to use managed Dialogs. Rather than
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.rule_edit_choose_action));
builder.setAdapter(new ArrayAdapter(this, R.array.dummyValues), null);
builder.show();
you should use something like
myActivity.showDialog(0);
and then implement onCreateDialog() in your Activity. Your activity will then manage the dialog and re-show it when you re-orientate and it's closed. If you need to change your dialog every time it is shown, implement onPrepareDialog() also - the Activity will give you access to the Dialog just before it is shown so you can update it (with a custom message, for instance).
There's lots of info here:
http://developer.android.com/guide/topics/ui/dialogs.html
As #Ciril said, your issue is that your Activity is restarted when you re-orientate. You could always fix your activity orientation to portrait or landscape if that is suitable for your app. That would prevent it from restarting.
most likely you use AlertDialog for your popups, something along the lines of:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.popup_title);
builder.setMessage(R.string.popup_message);
builder.setPositiveButton(R.string.yes, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do something
}
});
builder.show();
this is bad, because your Activity has no idea there's a popup dialog, and when you change screen orientation, the Activity is restarted with the new parameters, and your popup is gone.
to avoid this you'd better use ShowDialog() to display your popups. to make it work, you need to override onCreateDialog() :
// Called to create a dialog to be shown.
#Override
protected Dialog onCreateDialog(int id, Bundle bundle) {
switch (id) {
case NEW_DIALOG :
return new AlertDialog.Builder(this)
.setTitle(R.string.popup_title)
.setMessage(R.string.popup_message)
.setPositiveButton(android.R.string.ok, null)
.create();
default:
return null;
}
}
then you'd better override onPrepareDialog() (this is not required, actually):
// If a dialog has already been created, this is called
// to reset the dialog before showing it a 2nd time. Optional.
#Override
protected void onPrepareDialog(int id, Dialog dialog, final Bundle bundle) {
AlertDialog dlg = (AlertDialog) dialog;
switch (id) {
case NEW_DIALOG :
dlg.SetTitle("popup title");
// and maybe something else
}
}
after all preparations you may call ShowDialog(NEW_DIALOG) and you Activity will remember it has a popup laid over on the top, and will recreate it after the orientation change.
Related
I created two fairly long functions which create an AlertDialogBuilder which builds an AlertDialog which is populated and launched. The alert dialogs produced are fairly large for dialogs, so a lot of views need to be populated within the dialog. For the sake of cleanliness, testability, SRP etc. I decided to move these functions into a new class.
Originally the functions were placed directly in the Activity class, and the alert dialogs launched fine. I've now moved both to an AlertDialogLauncher class, which takes an Activity parameter when launched, most of the original code is the same, I've got the alert dialog working, but the colours of the text and background colours of some of my views are off.
So the dialog is launching fine, just with incorrect colours, so I imagine it is loading an incorrect style or something similar?
Code...
Original version (shortened)
private void addNormalRow(final ScannedWiFiNetwork network) {
TableRow row = (TableRow) View.inflate(this, R.layout.regular_network_table_row, null);
// loads of code
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
launchNewNetworkDialog(network);
}
});
}
private void launchPreferredNetworkDialog(final ScannedWiFiNetwork network) {
final AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Connect to "+network.getSsid()+"?")
.setView(getLayoutInflater().inflate(R.layout.preferred_network_dialog,null))
.setCancelable(false)
.show();
final EditText passwordInput = (EditText) dialog.findViewById(R.id.edit_text_password);
TextView passwordText = (TextView) dialog.findViewById(R.id.dialog_password);
//loads of code
}
Essentially, the launch dialog function is called and creates a new AlertDialog by passing the AlertDialog.Builder a reference to this (the Java class for my activity).
Refactored Activity/Interface class
private void addNormalRow(final ScannedWiFiNetwork network) {
TableRow row = (TableRow) View.inflate(this, R.layout.regular_network_table_row, null);
//loads of code
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Activity activity = (Activity) v.getContext();
dialogs.launchNewNetworkDialog(network, activity);
}
});
}
New AlertDialogLauncher class
public void launchPreferredNetworkDialog(final ScannedWiFiNetwork network, final Activity activity) {
Context con = activity.getApplicationContext();
LayoutInflater layoutInflater = LayoutInflater.from(con);
final AlertDialog dialog = new AlertDialog.Builder(activity)
.setTitle("Connect to "+network.getSsid()+"?")
.setView((layoutInflater.inflate(R.layout.preferred_network_dialog,null)))
.setCancelable(false)
.show();
As you can see, in this new class an Activity must be passed in to be used to create the layout inflater and context objects used later on to populate the views. All this works fine, however as mentioned earlier, the text colours change and the background of the buttons.
I'm loading the same xml layout file, so I'd assume it is loading an incorrect or default style somehow when I provide it with a default activity object (retrieved from calling getContext on the button view added to the dialog).
I've tried replacing 'activity' with NetworkListActivity.this (my activity name), that compiles but gives me the same ruined style outcome.
Thanks in advance for any help. Hope the question is clear!
Figured out my problem.. I never applied a style to my dialog xml layout file, some of the text views which I did not assign explicit text colors two are defaulting to the style of the dialog, I found this out when experimenting with changing the style which can be done by adding R.style.STYLE_NAME to the AlertDialogBuilder constructor (after the 'activity' parameter).
So yeah, I just didn't apply a style and need to be careful with views I haven't applied a style to!
I'd like to show an Alert Dialog which does not hide action bar. Is it possible to do it? The code which I tried is:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("Basemap selection");
builder.setSingleChoiceItems(new String[]{"Create cache", "Use existing file"}, 0, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Some logic here.
}
});
builder.setNegativeButton(R.string.common_cancel, null);
builder.create().show();
It covers the whole screen but I need the action bar to be available while dialog is showing. I know that it might violate some android rules but UX department wants it.
The screenshot is:
If you want to make a non-modal dialog (allowing the user to tap outside the dialog and access the Action Bar while the dialog is visible), there's some information here that may be helpful: timed modeless dialog, specifically the use of dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); - called after your dialog is visible.
The option is to change the activity to the Dialogue.Its simple process create an activity and goes to manifest file and set the theme of activity as
#android:style/Theme.DeviceDefault.Dialog
I have an activity that is using the Theme.Dialog style such that it is a floating window over another activity. However, when I click outside the dialog window (on the background activity), the dialog closes. How can I stop this behaviour?
To prevent dialog box from getting dismissed on back key pressed use this
dialog.setCancelable(false);
And to prevent dialog box from getting dismissed on outside touch use this
dialog.setCanceledOnTouchOutside(false);
What you actually have is an Activity (even if it looks like a Dialog), therefore you should call setFinishOnTouchOutside(false) from your activity if you want to keep it open when the background activity is clicked.
EDIT: This only works with android API level 11 or greater
What worked for me was to create DialogFragment an set it to not be cancelable:
dialog.setCancelable(false);
This could help you. It is a way to handle the touch outside event:
How to cancel an Dialog themed like Activity when touched outside the window?
By catching the event and doing nothing, I think you can prevent the closing. But what is strange though, is that the default behavior of your activity dialog should be not to close itself when you touch outside.
(PS: the code uses WindowManager.LayoutParams)
When using dialog as an activity in the onCreate add this
setFinishOnTouchOutside(false);
For higher API 10, the Dialog disappears when on touched outside, whereas in lower than API 11, the Dialog doesn't disappear. For prevent this, you need to do:
In styles.xml: <item name="android:windowCloseOnTouchOutside">false</item>
OR
In onCreate() method, use: this.setFinishOnTouchOutside(false);
Note: for API 10 and lower, this method doesn't have effect, and is not needed.
Setting the dialog cancelable to be false is enough, and either you touch outside of the alert dialog or click the back button will make the alert dialog disappear. So use this one:
setCancelable(false)
And the other function is not necessary anymore:
dialog.setCanceledOnTouchOutside(false);
If you are creating a temporary dialog and wondering there to put this line of code, here is an example:
new AlertDialog.Builder(this)
.setTitle("Trial Version")
.setCancelable(false)
.setMessage("You are using trial version!")
.setIcon(R.drawable.time_left)
.setPositiveButton(android.R.string.yes, null).show();
Alert Dialog is deprecated so use Dialog dialog = new Dialog(this);
For prevent close on outside touch
dialog.setCanceledOnTouchOutside(false);
Use This Code it's Working For me
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setCancelable(false);
Dialog dialog = new Dialog(context)
dialog.setCanceledOnTouchOutside(true);
//use this to dismiss the dialog on outside click of dialog
dialog.setCanceledOnTouchOutside(false);
//use this for not to dismiss the dialog on outside click of dialog.
Watch this link for more details about dialog.
dialog.setCancelable(false);
//used to prevent the dismiss of dialog on backpress of that activity
dialog.setCancelable(true);
//used to dismiss the dialog on onbackpressed of that activity
Simply,
alertDialog.setCancelable(false);
prevent user from click outside of Dialog Box.
I use this in onCreate(), seems to work on any version of Android; tested on 5.0 and 4.4.x, can't test on Gingerbread, Samsung devices (Note 1 running GB) have it this way by default:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
setFinishOnTouchOutside(false);
}
else
{
getWindow().clearFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
}
super.onCreate(savedInstanceState);
Use setFinishOnTouchOutside(false) for API > 11 and don't worry because its android's default behavior that activity themed dialog won't get finished on outside touch for API < 11 :) !!Cheerss!!
alert.setCancelable(false);
alert.setCanceledOnTouchOutside(false);
I guess this will help you.It Worked For me
Here is my solution:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Select The Difficulty Level");
builder.setCancelable(false);
Also is possible to assign different action implementing onCancelListener:
alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
#Override
public void onCancel(DialogInterface dialogInterface) {
//Your custom logic
}
});
I was facing the same problem. To handle it I set a OntouchListener to the dialog and do nothing inside. But Dialog dismiss when rotating screen too. To fix it I set a variable to tell me if the dialog has normally dismissed. Then I set a OnDismissListener to my dialog and inside I check the variable. If the dialog has dismmiss normally I do nothin, or else I run the dialog again (and setting his state as when dismissing in my case).
builder.setCancelable(false);
public void Mensaje(View v){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("¿Quieres ir a el Menú principal?");
builder.setMessage("Al presionar SI iras a el menú y saldras de la materia.");
builder.setPositiveButton("SI", null);
builder.setNegativeButton("NO", null);
builder.setCancelable(false);
builder.show();
}
In jetpack compose, use dismissOnClickOutside = false property to prevent from closing.
AlertDialog(
title = {
Text("Title")
},
text = {
Text(text = name)
},
onDismissRequest = onDismiss,
confirmButton = {
TextButton(onClick = onDismiss ) {
Text("Yes")
}
},
dismissButton = {
TextButton(onClick = onDismiss ) {
Text("Cancel")
}
},
properties = DialogProperties(
dismissOnClickOutside = false
)
)
}
This is the perfect answer to all your questions.... Hope you enjoy coding in Android
new AlertDialog.Builder(this)
.setTitle("Akshat Rastogi Is Great")
.setCancelable(false)
.setMessage("I am the best Android Programmer")
.setPositiveButton("I agree", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create().show();
i want to have in my application an alertdialog, that has its message updated everytime it is showed.
This is because the dialog box value depends on some values on the application.
Now i tried to use the showDialog method:
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
showDialog(RESULT_DIALOG);
return false;
}
But once the dialog is created, it doesn't change the message (i know that if the dialog is created, it use the started version).
My onCreateDialog method code is:
public Dialog onCreateDialog(int dialogId) {
AlertDialog dialog;
switch(dialogId) {
case RESULT_DIALOG:
// do the work to define the pause Dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(localTv.getText())
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
dialog = builder.create();
break;
default:
dialog = null;
}
return dialog;
}
There is a way to update the content of the AlertDialog.
Actually i create a new dialog box every time the onTouch event is called. But i'm not sure that it is the cleanest way to solve that problem.
Any idea?
Thanks :)
You have to use onPrepareDialog method:
#Override
protected void onPrepareDialog ( int id, Dialog dialog ) {
switch ( id ) {
case RESULT_DIALOG:
AlertDialog alertDialog = ( AlertDialog ) dialog;
alertDialog.setMessage( localTv.getText() );
break;
}
super.onPrepareDialog( id, dialog );
}
From http://developer.android.com/guide/topics/ui/dialogs.html :
Before the dialog is displayed, Android also calls the optional
callback method onPrepareDialog(int, Dialog). Define this method if
you want to change any properties of the dialog each time it is
opened. This method is called every time a dialog is opened, whereas
onCreateDialog(int) is only called the very first time a dialog is
opened. If you don't define onPrepareDialog(), then the dialog will
remain the same as it was the previous time it was opened. This method
is also passed the dialog's ID, along with the Dialog object you
created in onCreateDialog().
You can always change the dialog using onPrepareDialog or you can remove the dialog (so it will always pass through onCreateDialog) setting the onDismiss (dialog.setOnDismiss) to remove the dialog id (removeDialog(id)).
I have an android app which is already handling changes for orientation, i.e. there is a android:configChanges="orientation" in the manifest and an onConfigurationChange() handler in the activity that switches to the appropriate layout and preps it. I have a landscape / portrait version of the layout.
The problem I face is that the activity has a dialog which could be open when the user rotates the device orientation. I also have a landscape / portrait version of the dialog.
Should I go about changing the layout of the dialog on the fly or perhaps locking the activity's rotation until the user dismisses the dialog.
The latter option of locking the app appeals to me since it saves having to do anything special in the dialog. I am supposing that I might disable the orientation when a dialog opens, such as
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
and then when it dismisses
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
Would that be a sensible thing to do? If the screen orientation did change while it was locked, would it immediately sense the orientation change when it was unlocked?
Are there alternatives?
I would recommend not turning off the screen rotation, instead of this handle the configuration changes for the Dialog. You could use one of these two approach for this:
The first one is using a flag variable in onSaveInstanceState(outState) method, and restore the dialog onCreate(bundle) method:
in this example my flag variable is called 'isShowing Dialog', when the onCreate method is called by the android System for first time, the bundle argument will be null and nothing happens. However when the activity it's recreated by a configuration change (screen rotation), the bundle will have the boolean value isShowing Dialog, previously saved by the inSaveInstanceState(...) method, so if the variable gets true the dialog is created again, the trick here is set the flag in true when the dialog get showing, and false when it's not, is a little but simple trick.
Class MyClass extends Activity {
Boolean isShowingDialog = false;
AlertDialog myDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
if(savedInstanceState!=null){
isShowingDialog = savedInstanceState.getBoolean("IS_SHOWING_DIALOG", false);
if(isShowingDialog){
createDialog();
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("IS_SHOWING_DIALOG", isShowingDialog);
super.onSaveInstanceState(outState);
}
#Override
protected void onPause() {
if(myDialog!=null && myDialog.isShowing()) {
myDialog.dismiss();
}
}
private void createDialog() {
AlertDialog.Builder dialog_builder = new AlertDialog.Builder(this);
dialog_builder.setTitle("Some Title"):
... more dialog settings ...
myDialog = dialog_builder.create();
myDialog.show();
isShowingDialog = true;
}
private void hideDialog(){
myDialog.dismiss();
isShowingDialog = false;
}
}
The second approach is to use the ability of the fragments components to retain its states, the main idea is create the dialog inside a fragment, there is the problem about detach and reattach the fragment during the configuration changes (because you need dismiss and show the dialog correctly), but the solution is very similar to the first approach. The advantage of this approach is that if you have an AlertDialog with a couple of configurations, when the fragment is recreated there is not needed to create and setting up the dialog again, only make it show() and the AlertDialog state is maintained by the fragment.
I hope this helps.
I suggest your Dialog should override onSaveInstanceState() and onRestoreInstanceState(Bundle) to save its state into a Bundle.
You then override those methods in your Activity, checking if the Dialog is shown and if so - calling the dialog's methods to save and restore it's state.
If you are displaying this dialog from a fragment, you will want to override OnActivityCreated(Bundle) instead of OnRestoreInstanceState.
For a source example see the built-in clock app provided with Android, where the SetAlarm Activity handles the TimePickerDialog this way.
If you are handling orientation changes yourself, then here is an approach.
I won't claim that this is an elegant solution, but it works:
You can keep track of whether the dialog has an active instance inside the dialog class itself, by using a static variable activeInstance, and overriding onStart() to set activeInstance = this and onCancel() to set activeInstance = null.
Provide a static method updateConfigurationForAnyCurrentInstance() that tests that activeInstance variable and, if non-null, invokes a method activeInstance.reInitializeDialog(), which is a method that you will write to contain the setContentView() call plus the code that wires the handlers for the dialog controls (button onClick handlers, etc. - this is code that would normally appear in onCreate()). Following that, you would restore any displayed data to those controls (from member variables in your dialog object). So, for example, if you had a list of items to be viewed, and the user were viewing item three of that list before the orientation change, you would re-display that same item three at the end of updateConfigurationForAnyCurrentInstance(), right after re-loading the controls from the dialog resource and re-wiring the control handlers.
You would then call that same reInitializeDialog() method from onCreate(), right after super.onCreate(), and place your onCreate()-specific initialization code (e.g., setting up the list of items from which the user could choose, as described above) after that call.
This will cause the appropriate resource (portrait or landscape) for the dialog's new orientation to be loaded (provided that you have two resources defined having the same name, one in the layout folder and the other in the layout-land folder, as usual).
Here's some code that would be in a class called YourDialog:
ArrayList<String> listOfPossibleChoices = null;
int currentUserChoice = 0;
static private YourDialog activeInstance = null;
#Override
protected void onStart() {
super.onStart();
activeInstance = this;
}
#Override
public void cancel() {
super.cancel();
activeInstance = null;
}
static public void updateConfigurationForAnyCurrentInstance() {
if(activeInstance != null) {
activeInstance.reInitializeDialog();
displayCurrentUserChoice();
}
}
private void reInitializeDialog() {
setContentView(R.layout.your_dialog);
btnClose = (Button) findViewById(R.id.btnClose);
btnClose.setOnClickListener(this);
btnNextChoice = (Button) findViewById(R.id.btnNextChoice);
btnNextChoice.setOnClickListener(this);
btnPriorChoice = (Button) findViewById(R.id.btnPriorChoice);
btnPriorChoice.setOnClickListener(this);
tvCurrentChoice = (TextView) findViewById(R.id.tvCurrentChoice);
}
private void displayCurrentUserChoice() {
tvCurrentChoice.setText(listOfPossibleChoices.get(currentUserChoice));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
reInitializeDialog();
listOfPossibleChoices = new ArrayList<String>();
listOfPossibleChoices.add("One");
listOfPossibleChoices.add("Two");
listOfPossibleChoices.add("Three");
currentUserChoice = 0;
displayCurrentUserChoice();
}
#Override
public void onClick(View v) {
int viewID = v.getId();
if(viewID == R.id.btnNextChoice) {
if(currentUserChoice < (listOfPossibleChoices.size() - 1))
currentUserChoice++;
displayCurrentUserChoice();
}
}
else if(viewID == R.id.btnPriorChoice) {
if(currentUserChoice > 0) {
currentUserChoice--;
displayCurrentUserChoice();
}
}
Etc.
Then, in your main activity's onConfigurationChanged() method, you would just invoke YourDialog.updateConfigurationForAnyCurrentInstance() whenever onConfigurationChanged() is called by the OS.
Doesn't seem the title was ever resolved (Google Necro Direct).
Here is the solution, matching the request.
When your activity is created, log the screen orientation value.
when onConfiguration change is called on your activity, compare the orientation values. if the values don't match, fire off all of your orientation change listeners, THEN record the new orientation value.
Here is some constructive code to put in your activity (or any object that can handle configuration change events)
int orientation; // TODO: record orientation here in your on create using Activity.this.getRequestedOrientation() to initialize!
public int getOrientation(){return orientation;}
public interface OrientationChangeListener {
void onOrientationChange();
}
Stack<OrientationChangeListener> orientationChangeListeners = new Stack<>();
public void addOrientationChangeListener(OrientationChangeListener ocl){ ... }
public void removeOrientationChangeListener(OrientationChangeListener ocl){ ... }
That's the basic environment. Here's your executive:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (orientation != newConfig.orientation)
for (OrientationChangeListener ocl:orientationChangeListeners) ocl.onOrientationChange();
orientation = newConfig.orientation;
}
In YOUR code model, you may need to send the new configuration, with the event, or the two orientation values with the event. However, Activity.this.getOrientation() != Activity.this.getRequestedOrientation() during event handling (because we are in a logical state of change between two logical values).
In review of my post, i have determined that there could be some synchronization issues, with multiple events! This is not a fault of this code, but a fault of "Android Platform" for not having defacto orientation sense handlers on every window, thusly trashing the polymorphic benefits of using java in the first place..
See the answer from Viktor Valencia above. That will work perfectly with the slight adjustment that you move the createDialog() to onResume.
#Override
protected void onResume() {
super.onResume();
if(isShowingDialog){
createDialog();
}
}
Fetch the boolean isShowingDialog value at onCreate, as suggested, but wait for onResume to display the dialog.