PopupWindow
From API level 1 and onward you can place your content into a PopupWindow
, which is a new temporary window in which you can place views that will be displayed on top of the current activity window. PopupWindow
can be shown anywhere onscreen, either by providing an explicit location or by providing an existing view that the PopupWindow
should be anchored to.
PopupWindow
is used to show floating view on display at specified position, but without inserting or otherwise modifying the existing view hierarchy. It’s a floating container that appears on top of current activity. PopupWindow
can have their own layout and can be set after inflating with setContentView(View)
.
From API level 18 and onward you can use the newer ViewOverlay
to draw content on top of your views. ViewOverlay
allows you to add any number of Drawable
objects to a private layer managed by the parent view. Those objects will be drawn on top of the corresponding view as long as their bounds are within the bounds of the parent.
In order to draw content on top of our view hierarchy, we first need to create the content to display. Following listing (file res/layout/popup.xml) constructs a simple group of views that will be the content of our PopupWindow.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="This is a PopupWindow" /> <EditText android:layout_width="250dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> <Button android:id="@+id/btnClose" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="Close" /> </LinearLayout>
When we display this content in a pop-up anchored to a view, by default the PopupWindow
will display just below the view, left-aligned. However, if there is not enough space below the view to display the PopupWindow
, it will be displayed above the anchor view instead. To make the pop-up visually distinct in both cases, we can provide a custom background drawable that switches on the android:state_above_
anchor
attribute. Following listing (file res/drawable/popup_background.xml) illustrates the custom drawables we will be using for this example.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_above_anchor="true" android:drawable="@drawable/android_popup_bg_top" /> <!-- Default State --> <item android:drawable="@drawable/android_popup_bg_bottom" /> </selector>
Following listings (file res/layout/activity_main.xml) illustrates an example activity and layout that construct and display a PopupWindow
in response to a button click. In this example, the PopupWindow
will be shown anchored to the button that was clicked.
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Show PopupWindow" android:onClick="onShowWindowClick" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:text="Show PopupWindow" android:onClick="onShowWindowClick" /> </FrameLayout>
Some words about events in PopupWindow
.
setTouchInterceptor
. Default behavior is not to allow any elements in the PopupWindow
to be interactive, but to enable touch events to be delivered directly to the PopupWindow
. All outside touches will be delivered to the main Activity
window.setFocusable
. Call setFocusable()
to enable elements in the PopupWindow
to take focus, which will also enable the behavior of dismissing the PopupWindow
on any outside touch.setOutsideTouchable
. Call setOutsideTouchable()
if you want to enable outside touches to auto-dismiss the PopupWindow
but don't want elements inside the PopupWindow
to take focus.Following is activity displaying a PopupWindow
.
public class MainActivity extends Activity private PopupWindow popup; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //inflate the popup content layout; we do not have access //to the parent view yet, so we pass null as the //container view parameter. View popupContent = getLayoutInflater().inflate(R.layout.popup, null); popup = new PopupWindow(); //popup should wrap content view popup.setWindowLayoutMode( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT); popup.setHeight(250); popup.setWidth(350); //set content and background popup.setContentView(popupContent); popup.setBackgroundDrawable(getResources().getDrawable(R.drawable.popup_background)); popupContent.findViewById(R.id.btnClose).setOnClickListener(new View.OnClickListener() { public void onClick(View v) { popup.dismiss(); } }); popup.setTouchInterceptor(this); popup.setFocusable(true); popup.setOutsideTouchable(true); } @Override protected void onPause() { super.onPause(); popup.dismiss(); } @Override public boolean onTouch(View v, MotionEvent event) { //Handle direct touch events passed to the PopupWindow return false; } public void onShowWindowClick(View v) { if (popup.isShowing()) { popup.dismiss(); } else { //Show the PopupWindow anchored to the button we //pressed. It will be displayed below the button //if there's room, otherwise above. popup.showAsDropDown(v); } } }
In this example, we create a simple layout with two buttons, both set to trigger the same action. When either button is clicked, the PopupWindow
will be displayed anchored to that view by using the showAsDropDown()
method.
A PopupWindow
can also be shown at a specific location by using its showAtLocation()
method instead. Similar to showAsDropDown()
, this method takes a View
parameter, but it is used only to get window information.
popup.showAtLocation(layout, Gravity.CENTER, 0, 0);
After playing with the previous example, you may have noticed that the PopupWindow
has a default animation associated with it when it is shown or dismissed. This can be customized or removed by passing a new resource via setAnimationStyle()
. This method takes a resource ID referencing a style that defines a pair of animations, one for the window entrance and another for the window exit. So, set a custom animation enter/exit pair, or 0 to disable animations. You can also use animation styles defined in the platform, such as android.R.style.Animation_Toast
.
Following listing (file res/values/styles.xml) illustrates the style resource we need to create in order to customize the `PopupWindow
animation.
<resources> <!-- Define this element below any existing themes --> <style name="PopupAnimation"> <item name="android:windowEnterAnimation"> @android:anim/slide_in_left</item> <item name="android:windowExitAnimation"> @android:anim/slide_out_right</item> </style> </resources>
Add following snippet to MainActivity.java file.
popup.setAnimationStyle(R.style.PopupAnimation);
Result
ViewOverlay
From API level 18 and onward you can draw content over your views via ViewOverlay
. ViewOverlay
, and its cousin ViewGroupOverlay
, allows you to add any number of drawable objects to be drawn on top of the view. Applications cannot create a ViewOverlay
directly, and instead obtain a ViewOverlay
by calling getOverlay()
on any view in the hierarchy. Views are constrained to drawing within their bounds, so any content in an overlay whose location extends outside the hosting view’s bounds will be clipped.