I need to be notified when there are changes on the screen. Currently I am using
this.getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
Log.d("TAG", "GLOBAL LAYOUT");
}
});
But it doesn't work when dialog(custom, alert, progress, etc.) is shown or dismissed. I understand that dialogs are shown on another overlay so listener isn't attached to them. How can I get my desired functionality?
You probably need a dialog.setOnDismissListener or dialog.setOnCancelListener
They'll be called when something related to dialog dismissal happens or is being canceled.
Related
I have a RecyclerView and have an undo-functionality, where you delete an item but can press undo on the appearing Snackbar to insert the item back into the list.
Now unfortunately, this happens:
When deleting elements quickly in a row, some of them are being restored while deleting another. It seems like creating a second Snackbar too quickly after the first triggers the Action, e.g. in this case the undo.
Could this be the case, or is it my code that is faulty?
The code isn't too complex:
private void deleteSATemp(int position) {
SelfAffirmation saToDelete = selfAffirmations.get(position);
String content = saToDelete.getContent();
String partOfContent = content.substring(0, 20);
selfAffirmations.remove(position);
notifyItemRemoved(position);
createUndoSnackbar(saToDelete, position, partOfContent);
}
This is the "fake" removal part, where the element is removed from the list visually but not from the database yet, in case of an undo action.
And here is the Snackbar part:
private void createUndoSnackbar(SelfAffirmation saToDelete, int position, String pieceOfSAContent) {
Snackbar snackbar = Snackbar.make(((Activity) mContext).findViewById(R.id.sa_activity_parent_layout), mContext.getString(R.string.snackbarItemDeletedPlaceholder, pieceOfSAContent),
5000);
snackbar.setAction(R.string.snackbarUndoText, view -> {
selfAffirmations.add(position, saToDelete);
notifyItemInserted(position);
});
snackbar.addCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar snackbar, int event) {
if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
mCallbackListener.onItemDeleted(saToDelete);
}
}
});
snackbar.show();
}
The database works with LiveData. I can't imagine that this Android feature would be implemented so carelessly, so it has to be my code.
Yes, IMO you're right in your supposition of events popping up too fast.
According to Snackbar's Documentation you can only have one snackbar displayed at a time.
Snackbars appear above all other elements on screen and only one can be displayed at a time.
They automatically disappear after a timeout or after user interaction elsewhere on the screen, particularly after interactions that summon a new surface or activity. Snackbars can be swiped off screen.
When another snackbar appears the first one is automatically dismissed.
In the other hand: please review how you are implementing this selfAffirmations.remove(position); call. If you are removing positions in an array, and two calls to this method arise at about the same time this can produce unexpected behavior. You'd better search and delete by something unique and non-transferable (the current position of all items will change if you delete the first one), like an id. Cheers.
So,
I have an activity with a layout, and in this layout I only have one button.
when clicking this button, the activity sets the visibility of the button to invisible, and launches a popup window.
I implemented a simple onDismiss function in this popup, which sets the button to visible
pw.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
MainActivity.packButton.setVisibility(View.VISIBLE);
}
});
the problem is that sometimes, not very often, after the popup is dismissed, the button is shown, but only the top part of it, something like 1/5 of the button.
I suspected that the button became visible before the popup dismissed completely, and a sort of a clash happened between them, but on the other hand I made some checks and the popup window and the button are able to be shown at the same time without a problem, so a "layout clash" cannot be the reaon, right?
You can add delay and run this method on a handler.
pw.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
MainActivity.packButton.setVisibility(View.VISIBLE);
}
}, 1000);
};
});
I would suggest making the button variable non static and instead call a method of your activity from your listener and in this method set the button visibility. Having the button as a static variable could mean that although it is non null the button isn't added to the activities view at the point when you call to set is visibility.
I have a View say anchor and a PopupWindow pop. pop is shown with showAsDropDown when I click a button on anchor.
What I want is to show pop automatically at the first time anchor comes to screen. So I override onAttachedToWindow and add a onGlobalLayoutListener and show pop in it. see below:
private boolean mFirstRun = true;
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if(mFirstRun) {
mFirstRun = false;
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
showPopup();
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
}
The result is, only the first time (see above) pop will stay right above anchor. I have confirmed the width and height of pop is correct. when the button click triggers, pop is shown at the proper place.
After spending some time I found the problem is in onGlobalLayoutListener anchor.getLocationOnScreen has a larger value than the final value so there's no enough space for pop below it.
How can I fix this? and why the screen location is incorrect in that listener?
I'm having a problem when setting the visibility of two image buttons one on top of the other. The idea is to implement a play/pause control. The problem is that the only part where setting the visibility actually works is in the click listeners of the buttons. If I try to change it somewhere else nothing happens. Any idea why is this happening?
playBtn.setOnClickListener(new OnClickListener() {//PLAY BUTTON LISTENER
public void onClick(View v) {
playBtn.setVisibility(ImageButton.GONE);
pauseBtn.setVisibility(ImageButton.VISIBLE);
mp.start();
}});
pauseBtn.setOnClickListener(new OnClickListener() {//PAUSE BUTTON LISTENER
public void onClick(View v) {
pauseBtn.setVisibility(ImageButton.GONE);
playBtn.setVisibility(ImageButton.VISIBLE);
mp.pause();
}});
final class SeekBarTask extends TimerTask {
public SeekBarTask(int duration) {
}
#Override
public void run() {
if(seekBar.getProgress() >= mp.getDuration()) {//IF SONG HAS FINISHED...
pauseBtn.setVisibility(ImageButton.GONE);//THESE ONES
playBtn.setVisibility(ImageButton.VISIBLE);//DOESN'T WORK
mp.stop();
}
else {
seekBar.incrementProgressBy(100);
}
}
}
I would recommend just changing the icon of one ImageButton.
I would think only one of two things could be happening. Either this code never gets hit, or the variables are not referring to the same object instances you're expecting them to. Have you put a breakpoint inside that condition? I would check that a break point even gets hit in there, and then check that the variables are pointing at the correct button instances.
Without seeing the rest of the code I have to ask...why are you checking on a progress bar for a "finished playing" condition versus using the media players on completion callback?
I'm doing something very similar, and I use the MediaPlayer's OnCompletionListener to flip the visibility of my buttons.
I don't remember the details of Android GUI manipulation but could it have to do that you're doing it from another thread and you're not supposed to?
i noticed that setting an ImageButton to View.INVISIBLE is not working when you have set an Animation to it. you have to remove the Animation then make it Invisible. bad pitfall i think...
I have a DialogPreference and I want to avoid the user from closing it when pressing "OK", "Cancel", etc.
How should I do that?
EDIT:
I tried to reach the OK button to disable when the dialog is created. But I couldn't make it :(
The solution is quite easy. Overwrite showDialog and set your own click listener to the buttons you want to intercept.
#Override
protected void showDialog(Bundle bundle) {
super.showDialog(bundle);
Button pos = ((AlertDialog) getDialog()).getButton(DialogInterface.BUTTON_POSITIVE);
pos.setOnClickListener(...);
}
In your click listener you can do the validation you want.
A tweak could be to create a custom dialog where you define your own buttons (OK and Close).
public class YourClass implements OnClickListener {
private Button DialogButton;
private Dialog dialog;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.MainLayout);
/* Your code... */
DialogButton = (Button) findViewById(R.id.DialogButtonId);
DialogButton.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.DialogButtonId:
LayoutInflater inflater = LayoutInflater.from(YourClass.this);
final View inflay = inflater.inflate(R.layout.DialogLayout, (ViewGroup) findViewById(R.id.RootIdOfDialogLayout));
TextView YourTextView = (TextView) inflay.findViewById(R.id.TextViewId);
Button cancel = (Button) inflay.findViewById(R.id.CancelButtonId);
cancel.setOnClickListener(YourClass.this);
Button ok = (Button) inflay.findViewById(R.id.OkButtonId);
ok.setOnClickListener(YourClass.this);
dialog = new Dialog(YourClass.this);
dialog.setContentView(inflay);
dialog.setTitle(getString(R.string.TitleStringId));
dialog.show();
break;
case R.id.CancelButtonId:
/* Checking if the user selected an option if true call dialog.dismiss() */
break;
case R.id.OkButtonId:
/* Here handle your preferences (e.g. putString(String key, String value)) */
/* Checking if the user selected an option if true call dialog.dismiss() */
break;
}
}
}
Check out http://developer.android.com/reference/android/content/SharedPreferences.Editor.html in order to handle your preference in onClick. I didn't test this code just wrote it to show you how you could solve it!
The dialog stays open until you call dialog.dismiss();. In that case you'll have to create your drop-down-menu, polls or what ever you want to display in your layout file. After pressing ok or cancel you should check if the user made a choice, and parse that choice into your preferences. (check link above)
Rgds
Layne
You could try opening it again.
Why would you want to prevent users to close the dialog? Users should be able to have 'full' control of their device.
You can see the source code of DialogPreferences here:
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/preference/DialogPreference.java
And then, copy most of it to your code, modifying the code as needed.
How about overriding the onDismiss() method and implementing a canExit() method with the validations you want to occcur? E.g. :
public class MyDialogPref extends DialogPreference {
#override public void onDismiss(DialogInterface dialog) {
if (canExit()) {
super.onDismiss(dialog);
}
}
...
}
A good UI should have a default selection/option already selected (the previously user-entered options or a program default).
Presenting a dialog asking for a change in options without any indication of what you already have is bad UI design.
This way if the user clicks Cancel, nothing changes and they saw what the option selected was. If they make no change and click OK then nothing really changes either.
Software is supposed to make doing specific tasks easier, not force the user to process the apps logic themselves.