3

While using Nougat's new multi-window mode, I noticed that a Toast will be displayed over another app if my own app is in the top window in portrait mode.

enter image description here

This is ... not good at all. So I tried positioning my Toast following this answer to "How to change position of Toast in Android?"

toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);

Unfortunately the Gravity seems to be interpreted as "gravity for the screen" not "gravity for my window".

How to get a Toast displayed somewhere near the bottom of my window and centered horizontally?

enter image description here

Community
  • 1
  • 1
Bö macht Blau
  • 12,820
  • 5
  • 40
  • 61

2 Answers2

3

I suspect this is the intended behaviour. Beyond there not being any straightforward way to achieve what you desire, according to the Material Design Guidelines Toasts are used primarily to convey system messages and should appear at the bottom of the screen.

My guess would be that any system messages should pertain to the device as a whole, and are not necessarily application specific, so this consistent behaviour makes sense. That said, I can see why this behaviour is undesirable, because the Toast ends up taking up practically 25% of the screen on one of the applications... however, regardless of the position of the Toast it will be gobbling up that screen real estate, whether it's on your application or the one below.

If you really wanted to implement a workaround, here is the implementation for offsetting the Toast vertically. A slight variation should achieve landscape mode, but it's a bit more finnicky.

View root = findViewById(R.id.root_main);

int[] xy = new int[2];
root.getLocationOnScreen(xy);

DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(displayMetrics);
int devHeight = displayMetrics.heightPixels;

int viewHeight = root.getHeight();

Toast toast = Toast.makeText(getApplicationContext(), "hello", Toast.LENGTH_LONG);
int yOffset = Math.abs(xy[1] - devHeight + viewHeight) + toast.getYOffset();
toast.setGravity(Gravity.BOTTOM, 0, yOffset);
toast.show();
Demonsoul
  • 791
  • 4
  • 11
  • thanks for answering, but I think Toasts may be used by every app for small messages, like the example in the [developer guide for Toast](https://developer.android.com/guide/topics/ui/notifiers/toasts.html) says. If there was a consensus that Toasts are only for system messages, why do they explain how to customize my Toast? I use them for things like "Game Over" or "Added 10 songs to playlist". – Bö macht Blau Oct 13 '16 at 13:39
  • (cont) I think it's really bad (even dangerous) if you use standard toasts and the users can't even see from which app the message came. And of course I don't want to cover another app's area. – Bö macht Blau Oct 13 '16 at 13:40
  • About the workaround: Could you show some code? I'd like to test this with my small sample app from the question. – Bö macht Blau Oct 13 '16 at 13:43
  • 1
    That's a very fair point. I think Android guidelines can be very conflicting at times since their big overhaul with 'Material Design'. Playing devil's advocate some more, though; if you're displaying a Toast from the user interacting with your app, is it really a crime to cover up the app with which they aren't interacting? – Demonsoul Oct 13 '16 at 13:43
  • Regardless, I think you are right and Google would be wise to add support for what you want... they maybe didn't consider the repercussions of Gravity on functions that operate on the Window rather than application – Demonsoul Oct 13 '16 at 13:44
  • On top of my "normal" toast problem the hints which you get by long clicking an action bar button also sometimes appear in the wrong window. At least on a 10" tablet if my app is in the left window and my window is half the screen width or less. I'm beginning to think this is a bug. – Bö macht Blau Oct 13 '16 at 13:47
  • 1
    (+1 because of all the good thoughts, even if I don't get my Toast positioned) And about the "is it really a crime"-question: I may be wrong but I thought users could watch a video (not my window) while writing a mail (my window). " In multi-window mode, an app can be in the paused state and still be visible to the user. An app might need to continue its activities even while paused. For example, a video-playing app that is in paused mode but is visible should continue showing its video." from [guide on multi-window](https://developer.android.com/guide/topics/ui/multi-window.html) – Bö macht Blau Oct 13 '16 at 13:58
  • and if my toast covers their video, guess which app will be uninstalled :( – Bö macht Blau Oct 13 '16 at 13:59
  • Thank you very much! This line was what I needed: `wm.getDefaultDisplay().getMetrics(displayMetrics);` I only knew that `getLocationOnScreen()` tells me where I am in multi window mode (more or less) but to calculate the xOffset and yOffset I needed the *screen* width and height. So to be fully compatible with Nougat I only have to stop using the SupportActionBar ;) For landscape I used `xOffset = (int)(0.5 * (width - root.getRight() );` respectively `xOffset = - (int)(...);` – Bö macht Blau Oct 13 '16 at 15:09
  • Awesome! Glad to help. Android N seems to have really exasperated the issue of having 50 methods that do the same thing... seems half of them now refer to the actual phone while the other half refer to what the Activity perceives as its window... and they aren't named appropriately at all! – Demonsoul Oct 13 '16 at 15:22
  • This multi-window mode is the first time for me that `getLocationInWindow(coords) != getLocationOnScreen(coords)`. And I'm really glad that you happened to see my question. Thanks once more and bye! – Bö macht Blau Oct 13 '16 at 15:31
0

use setGravity method with parameters: xOffset, yOffset.

Toast toast= Toast.makeText(getApplicationContext(),"Message Toast", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
sonnv1368
  • 1,547
  • 12
  • 17
  • thanks for answering but with `Gravity.CENTER_HORIZONTAL` the `Toast` is displayed in the middle of the whole screen in landscape, this means it will at least partly appear above the other app in my second picture. Gravity.TOP on the other hand will cause problems if my app is in portrait and in the lower window. Like I said: Gravity is related to the whole screen, not to my window. – Bö macht Blau Oct 13 '16 at 11:21