Android PopupMenu 与 PopupWindow(的区别)

平常的开发可能经常碰到PopupMenu和PopupWindow,但是不小心的话总是比较容易搞混淆了这两者,下面通过一个实例简单介绍下它们各自的使用方式。

实例的代码使用了Android Annotations,但是代码读起来应该是没有障碍的,如果不太了解AA的话,可以参考下此文

1.PopupMenu和PopupWindow

PopupMenu显示效果类似上下文菜单(Menu),而PopupWindow的显示效果实际上类似对话框(Dialog),两者效果如下图所示:

PopupMenu显示效果

image image

PopupWindow显示效果

image

2.实例基础代码

我们要实现的界面就是上面所示的界面,上下各有两个按钮,点击按钮分别在正确的位置弹出PopupMenu或者PopupWindow,下面是界面代码:

 
 
  1. <RelativeLayout
  2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="match_parent"
  6.     android:orientation="vertical"
  7.     android:paddingBottom="@dimen/activity_vertical_margin"
  8.     android:paddingLeft="@dimen/activity_horizontal_margin"
  9.     android:paddingRight="@dimen/activity_horizontal_margin"
  10.     android:paddingTop="@dimen/activity_vertical_margin"
  11.     tools:context="hujiawei.xiaojian.ui.PopupwindowActivity">
  12.  
  13.     <LinearLayout
  14.         android:layout_width="match_parent"
  15.         android:layout_height="wrap_content"
  16.         android:layout_alignParentTop="true"
  17.         android:orientation="vertical">
  18.  
  19.         <Button
  20.             android:id="@+id/window"
  21.             android:layout_width="match_parent"
  22.             android:layout_height="wrap_content"
  23.             android:text="show popup window"/>
  24.  
  25.         <Button
  26.             android:id="@+id/menu"
  27.             android:layout_width="match_parent"
  28.             android:layout_height="wrap_content"
  29.             android:layout_below="@id/window"
  30.             android:text="show popup menu"/>
  31.  
  32.     </LinearLayout>
  33.  
  34.     <LinearLayout
  35.         android:layout_width="match_parent"
  36.         android:layout_height="wrap_content"
  37.         android:layout_alignParentBottom="true"
  38.         android:orientation="vertical">
  39.  
  40.         <Button
  41.             android:id="@+id/bottomwindow"
  42.             android:layout_width="match_parent"
  43.             android:layout_height="wrap_content"
  44.             android:text="show popup window"/>
  45.  
  46.         <Button
  47.             android:id="@+id/bottommenu"
  48.             android:layout_width="match_parent"
  49.             android:layout_height="wrap_content"
  50.             android:layout_below="@id/window"
  51.             android:text="show popup menu"/>
  52.  
  53.     </LinearLayout>
  54.  
  55. </RelativeLayout>

3.实现PopupMenu

PopupMenu的实现稍微简单点,因为它就是普通的菜单!

(1)在res/menu文件夹下新建文件menu_popupmenu.xml

 
 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <menu
  3.     xmlns:android="http://schemas.android.com/apk/res/android"
  4.     xmlns:app="http://schemas.android.com/apk/res-auto">
  5.  
  6.     <item
  7.         android:id="@+id/item_movies"
  8.         android:title="Movies"
  9.         android:visible="true"
  10.         app:showAsAction="ifRoom|withText"/>
  11.     <item
  12.         android:id="@+id/item_music"
  13.         android:title="Music"
  14.         android:visible="true"
  15.         app:showAsAction="ifRoom|withText"/>
  16.     <item
  17.         android:id="@+id/item_photo"
  18.         android:title="Photo"
  19.         android:visible="true"
  20.         app:showAsAction="ifRoom|withText"/>
  21.  
  22. </menu>

(2)然后在Activity中创建Menu并处理MenuItem的点击事件

 
 
  1. @Click({R.id.menu, R.id.bottommenu})
  2. void menu(View view) {
  3.     PopupMenu popupMenu = new PopupMenu(this, view);
  4.     popupMenu.setOnMenuItemClickListener(this);
  5.     popupMenu.inflate(R.menu.menu_popupmenu);
  6.     popupMenu.show();
  7. }
  8.  
  9. public boolean onMenuItemClick(MenuItem item) {
  10.     switch (item.getItemId()) {
  11.         case R.id.item_photo:
  12.             toastUtil.showShortToast("Photo");
  13.             return true;
  14.         case R.id.item_movies:
  15.             toastUtil.showShortToast("Movies");
  16.             return true;
  17.         case R.id.item_music:
  18.             toastUtil.showShortToast("Music");
  19.             return true;
  20.     }
  21.     return false;
  22. }

从上面的代码可以看出,不论是点击上面的还是下面的show popup menu按钮,结果都是弹出在当前按钮附近显示PopupMenu (因为这里设置了button view为anchor view),而且它会自适应位置,在按钮的左下角或者左上角显示。

4.实现PopupWindow

实现PopupWindow稍微复杂些,但是自定义性更强,它可以将任意界面设置为PopupWindow。

(1)新建布局文件layout/window_popup.xml,作为PopupWindow,其中只有4个按钮,最后一个是取消按钮,用于关闭PopupWindow

 
 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3.     xmlns:android="http://schemas.android.com/apk/res/android"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="match_parent"
  6.     android:layout_marginLeft="@dimen/activity_horizontal_margin"
  7.     android:layout_marginRight="@dimen/activity_horizontal_margin"
  8.     android:background="@android:color/background_dark"
  9.     android:orientation="vertical">
  10.  
  11.     <LinearLayout
  12.         android:layout_width="match_parent"
  13.         android:layout_height="wrap_content"
  14.         android:orientation="vertical">
  15.  
  16.         <Button
  17.             android:id="@+id/music"
  18.             android:layout_width="match_parent"
  19.             android:layout_height="wrap_content"
  20.             android:text="Music"/>
  21.  
  22.         <Button
  23.             android:id="@+id/movie"
  24.             android:layout_width="match_parent"
  25.             android:layout_height="wrap_content"
  26.             android:text="Movie"/>
  27.  
  28.         <Button
  29.             android:id="@+id/photo"
  30.             android:layout_width="match_parent"
  31.             android:layout_height="wrap_content"
  32.             android:text="Photo"/>
  33.  
  34.     </LinearLayout>
  35.  
  36.     <LinearLayout
  37.         android:layout_width="match_parent"
  38.         android:layout_height="wrap_content"
  39.         android:layout_marginTop="10dp"
  40.         android:orientation="vertical">
  41.  
  42.         <Button
  43.             android:id="@+id/cancel"
  44.             android:layout_width="match_parent"
  45.             android:layout_height="wrap_content"
  46.             android:text="Cancel"/>
  47.     </LinearLayout>
  48.  
  49. </LinearLayout>

(2)在Activity中控制PopupWindow的显示和事件处理

 
 
  1. @Click
  2. void window(View view) {
  3.     if (popupWindow != null && popupWindow.isShowing()) {
  4.         return;
  5.     }
  6.     LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.window_popup, null);
  7.     popupWindow = new PopupWindow(layout,
  8.             ViewGroup.LayoutParams.MATCH_PARENT,
  9.             ViewGroup.LayoutParams.WRAP_CONTENT);
  10.  
  11.     popupWindow.setAnimationStyle(R.style.Popupwindow);//包括进入和退出两个动画
  12.     popupWindow.showAtLocation(view, Gravity.LEFT | Gravity.BOTTOM, 0, 0);
  13.     //popupWindow.showAsDropDown(view);
  14.  
  15.     setButtonListeners(layout);
  16. }
  17.  
  18. @Click
  19. void bottomwindow(View view) {
  20.     if (popupWindow != null && popupWindow.isShowing()) {
  21.         return;
  22.     }
  23.     LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.window_popup, null);
  24.     popupWindow = new PopupWindow(layout,
  25.             ViewGroup.LayoutParams.MATCH_PARENT,
  26.             ViewGroup.LayoutParams.WRAP_CONTENT);
  27.  
  28.     popupWindow.setAnimationStyle(R.style.Popupwindow);
  29.     int[] location = new int[2];
  30.     view.getLocationOnScreen(location);
  31.     popupWindow.showAtLocation(view, Gravity.LEFT | Gravity.BOTTOM, 0, -location[1]);
  32.     //popupWindow.showAsDropDown(view);
  33.  
  34.     setButtonListeners(layout);
  35. }
  36.  
  37. private void setButtonListeners(LinearLayout layout) {
  38.     Button music = (Button) layout.findViewById(R.id.music);
  39.     music.setOnClickListener(new View.OnClickListener() {
  40.         @Override
  41.         public void onClick(View view) {
  42.             if (popupWindow != null && popupWindow.isShowing()) {
  43.                 toastUtil.showShortToast("music");
  44.                 popupWindow.dismiss();
  45.             }
  46.         }
  47.     });
  48.  
  49.     Button movie = (Button) layout.findViewById(R.id.movie);
  50.     movie.setOnClickListener(new View.OnClickListener() {
  51.         @Override
  52.         public void onClick(View view) {
  53.             if (popupWindow != null && popupWindow.isShowing()) {
  54.                 toastUtil.showShortToast("movie");
  55.                 popupWindow.dismiss();
  56.             }
  57.         }
  58.     });
  59.  
  60.     Button photo = (Button) layout.findViewById(R.id.photo);
  61.     photo.setOnClickListener(new View.OnClickListener() {
  62.         @Override
  63.         public void onClick(View view) {
  64.             if (popupWindow != null && popupWindow.isShowing()) {
  65.                 toastUtil.showShortToast("photo");
  66.                 popupWindow.dismiss();
  67.             }
  68.         }
  69.     });
  70.  
  71.     Button cancel = (Button) layout.findViewById(R.id.cancel);
  72.     cancel.setOnClickListener(new View.OnClickListener() {
  73.         @Override
  74.         public void onClick(View view) {
  75.             if (popupWindow != null && popupWindow.isShowing()) {
  76.                 popupWindow.dismiss();
  77.             }
  78.         }
  79.     });
  80. }

从上面代码可以看出,点击上面和下面的按钮代码略微不同,因为这里我希望PopupWindow一直是从界面的底部慢慢滑入进入的,所以要控制下位置。关于PopupWindow的显示位置,它既提供了showAtLocation方法精确控制,也提供了showAsDropDown(view)方法简单控制。

滑入滑出的动画效果代码如下,需要注意的是,PopupWindow需要两个动画:一个进入,一个退出,如果只给定一个动画,可能会看不到动画的效果。

 
 
  1. /res/values/styles.xml
  2.  
  3. <style name="Popupwindow">
  4.     <item name="android:windowEnterAnimation">@anim/slide_in_bottom</item>
  5.     <item name="android:windowExitAnimation">@anim/slide_out_bottom</item>
  6. </style>
  7.  
  8. /res/anim/slide_in_bottom.xml
  9.  
  10. <?xml version="1.0" encoding="utf-8"?>
  11. <translate xmlns:android="http://schemas.android.com/apk/res/android"
  12.            android:interpolator="@android:anim/decelerate_interpolator"
  13.            android:fromYDelta="100%" android:toYDelta="0"
  14.            android:duration="400"/>
  15.  
  16. /res/anim/slide_out_bottom.xml
  17.  
  18. <?xml version="1.0" encoding="utf-8"?>
  19. <translate xmlns:android="http://schemas.android.com/apk/res/android"
  20.            android:interpolator="@android:anim/accelerate_interpolator"
  21.            android:fromYDelta="0" android:toYDelta="100%"
  22.            android:duration="200"/>

(3)使用PopupWindow还有不少需要注意的地方,例如你上面看到的代码中很多判断popupwindow是否为null或者是否正在显示等,有一个情况是,如果用户点击返回键,默认情况下Activity就要退出了,这个时候PopupWindow没有dismiss,容易出现内存泄露的报错,所以我们要处理下这个问题,如果用户点击返回键的时候PopupWindow正在显示的话那么就dismiss PopupWindow就好了。

 
 
  1. @Override
  2. public void onBackPressed() {
  3.     if (popupWindow != null && popupWindow.isShowing()) {
  4.         popupWindow.dismiss();
  5.     }else{
  6.         super.onBackPressed();
  7.     }
  8. }

OK,差不多就是这些了,希望会有帮助,Enjoy!:-)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值