Android PopupMenu 与 PopupWindow(的区别)

本文转载自(http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0721/3212.html)

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

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

1.PopupMenu和PopupWindow

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

PopupMenu显示效果

 

PopupWindow显示效果

2.实例基础代码

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

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

3.实现PopupMenu

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

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

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

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

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

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

4.实现PopupWindow

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

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

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

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

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

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

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

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

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

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

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


来源:http://hujiaweibujidao.github.io/blog/2015/07/04/android-popupmenu-and-popupwindow/
Written by hujiawei Posted at http://hujiaweibujidao.github.io

你可能感兴趣的:(Android)