Repositioning Toast Messages
I work on a large app that shows “business intelligence” reports. A feature of such reports allows the designer to add one or more images to the report along with more typical components like graphs and tables. The images can have “alt text”, and we want to show that in a Toast message if the user taps on the image. By default, Toast messages show up horizontally centered and near the bottom of the screen. Since that location may not be over the selected image, I decided to fix that by explicitly repositioning the Toast.
In the screen shot above, you can see two images inside of horizontal rectangles. Prior to the fix, tapping on the image of the dog, causes the Toast with the “alt text” message to display on top of the fighter jet.
The Toast class has a method for adjusting the position:
toast.setGravity(Gravity.CENTER, xOffset, yOffset);
The x and y offsets are relative to the position determined by your choice for the gravity parameter. By starting from a centered gravity, I’ll be moving the position to be over the tapped image by changing the offsets. As near as I can tell, (Gravity.CENTER, 0,0) represents the center of the screen so negative and positive offsets are needed to correctly position the Toast.
We use an OnClickListener to detect the tap, and the ImageView is the view supplied to the onClick(View v) method in the listener. To obtain the coordinates of the RelativeLayout holding the ImageView, I obtained the parent view of the image view, then called getGlobalVisibleRect(Rect gvr) on the parent. The “gvr” rectangle contains the coordinates of the view over which we want to position the Toast. Calling getRootView() on the image view gives us the outermost view of the app, and we can use its coordinates to represent the limits of the viewable area.
Now it is a matter of calculating the “center” of the image and expressing that as an appropriate x and y offset. I determined the center of the viewable area by dividing the root view’s right and bottom values in half. The center of the image’s parent view was trickier. Look at the comments in the code below to see how I did it.
public void onClick(View v) {
int xOffset = 0;
int yOffset = 0;
Rect gvr = new Rect();
View parent = (View) v.getParent();// v is the image,
//parent is the rectangle holding it.
if (parent.getGlobalVisibleRect(gvr)) {
Log.v("image left", Integer.toString(gvr.left));
Log.v("image right", Integer.toString(gvr.right));
Log.v("image top", Integer.toString(gvr.top));
Log.v("image bottom", Integer.toString(gvr.bottom));
View root = v.getRootView();
int halfwayWidth = root.getRight() / 2;
int halfwayHeight = root.getBottom() / 2;
//get the horizontal center
int parentCenterX = ((gvr.right - gvr.left) / 2) + gvr.left;
//get the vertical center
int parentCenterY = (gvr.bottom - gvr.top) / 2 + gvr.top;
if (parentCenterY <= halfwayHeight) {
yOffset = -(halfwayHeight - parentCenterY);//this image is above the center of gravity, i.e. the halfwayHeight
} else {
yOffset = parentCenterY - halfwayHeight;
}
if (parentCenterX < halfwayWidth) { //this view is left of center xOffset = -(halfwayWidth - parentCenterX); } if (parentCenterX >= halfwayWidth) {
//this view is right of center
xOffset = parentCenterX - halfwayWidth;
}
}
Toast toast = Toast.makeText(activity, altText, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, xOffset, yOffset);
toast.show();
}
});
Now knowing the center of the screen and center of the image, you can pass an appropriate x and y offset to the Toast. The sign of the offset will have to be negative for positions left and above the center.
Here’s the Toast showing over the image of the dog.
Now looking at a report with three images in portrait orientation, we see that the Toast is properly positioned horizontally.
As always, I’d like to hear about smarter ways to do these things.
-
December 3, 2012 at 1:01 pm | #1Android – Create a Toast anchored to a View : Android Community – For Application Development


