PopupWindow


官方文档对该控件的描述是:“一个弹出窗口控件,可以用来显示任意视图(View),而且会浮动在当前活动(activity)的顶部”。PopupWindow可以让我们实现多种自定义控件,例如:menu、alertdialog等弹窗似的View。

  • 改变PopupWindow的视图内容
    可以通过setContentView来改变popup的显示内容,也可以用来初始化PopupWindow的View,比如使用构造函数public PopupWindow (Context context)获得的Popupwindow就只能用setContentView来设置内容。
PopupWindow popupWindow = new PopupWindow(context);
popupWindow.setContentView(contentview);
  • 获得PopupWindow的视图内容
public View getContentView()
  • 显示PopupWindow

    • showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移
    • showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移
    • showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
  • 有两种方法设置PopupWindow的大小:

    • 调用有宽高参数的构造函数:
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentview = inflater.inflate(R.layout.popup_process, null);
PopupWindow popupWindow = new PopupWindow(contentview,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
  • 通过setWidth和setHeight设置
PopupWindow popupWindow = new PopupWindow(contentview);
popupWindow.setWidth(LayoutParams.WRAP_CONTENT);           
popupWindow.setHeight(LayoutParams.WRAP_CONTENT);
  • PopUpWindow的焦点:
    一般情况下setFocusable(true);
    其他任何事件的响应都必须发生在PopupWindow消失之后, (home 等系统层面的事件除外)。比如这样一个PopupWindow出现的时候,按back键首先是让PopupWindow消失,第二次按才是退出activity,准确的说是想退出activity你得首先让PopupWindow消失,因为不并是任何情况下按back PopupWindow都会消失,必须在PopupWindow设置了背景的情况下 。

  • 点击空白处的时候让PopupWindow消失
    要让点击PopupWindow之外的地方PopupWindow消失你需要调用setBackgroundDrawable(new BitmapDrawable());
    设置背景,为了不影响样式,这个背景是空的。还可以这样写,觉得这样要保险些:

setBackgroundDrawable(new ColorDrawable(0x00000000));

背景不为空但是完全透明。如此设置还能让PopupWindow在点击back的时候消失。


示例:
弹出框布局title_popupwindow.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content">  
  
    <ListView  
        android:id="@+id/popupwindow"  
        android:background="@drawable/title_background"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:divider="@drawable/title_background_line"  
        android:listSelector="@drawable/title_background_pressed"  //选中的时候背景图片
        android:cacheColorHint="@android:color/transparent">  //去除listview的拖动背景色
    </ListView>  
</RelativeLayout>  

弹出框的item的布局popupwindow_item.xml

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="fill_parent"  
    android:layout_height="wrap_content"  
    android:padding="8.0dip" >  
  
    <TextView  
        android:id="@+id/popup_item"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:textStyle="bold"  
        android:singleLine="true"  
        android:ellipsize="end"  
        android:textColor="#ffffffff"/>  
  
</RelativeLayout>  

写一个PopupWindow的派生类MyPopupWindow

public class MyPopupWindow extends PopupWindow {  
    /** 
     * 上下文对象 
     */  
    private Context mContext;  
    /** 
     * 回调接口对象 
     */  
    private OnPopupWindowClickListener listener;  
    /** 
     * ArrayAdapter对象 
     */  
    private ArrayAdapter adapter;  
    /** 
     * ListView的数据源 
     */  
    private List<String> list = new ArrayList<String>();  
    /** 
     * PopupWindow的宽度 
     */  
    private int width = 0;  
  
    public MyPopupWindow(Context context){  
        super(context);   
        mContext = context;  
        initView();  
    }  
      
    private void initView(){  
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
        View popupView = inflater.inflate(R.layout.title_popupwindow, null);  
        // 设置MyPopupWindow的View  
        this.setContentView(popupView);  
          
        //设置宽度,若没有设置宽度为LayoutParams.WRAP_CONTENT  
        this.setWidth(250);    
        this.setHeight(LayoutParams.WRAP_CONTENT);  
          
        //设置动画  
        this.setAnimationStyle(R.style.popupwindow_animation);  
          
        //设置ListView点击响应
        this.setFocusable(true);  
        // 实例化一个ColorDrawable颜色为半透明,点back键和其他地方使其消失
        this.setBackgroundDrawable(new ColorDrawable(0x00000000));   
        this.setOutsideTouchable(true);  
              
        ListView listView = (ListView) popupView.findViewById(R.id.popupwindow);  
        adapter = new ArrayAdapter(mContext, R.layout.popupwindow_item, R.id.popup_item, list);  
        listView.setAdapter(adapter);  
          
        //ListView的点击事件  
        listView.setOnItemClickListener(new OnItemClickListener() {  
  
            @Override  
            public void onItemClick(AdapterView<?> parent, View view,  
                    int position, long id) {  
                MyPopupWindow.this.dismiss();  //点击选项后,popupwindow消失
                if(listener != null){  
                    listener.onPopupWindowItemClick(position);  
                }  
            }  
        });  
          
    }  
      
    /** 
     * 为MyPopupWindow设置回调接口 
     * @param listener 
     */  
    public void setOnPopupWindowClickListener(OnPopupWindowClickListener listener){  
        this.listener = listener;  
    }  
      
  
    /** 
     * 设置数据的方法,供外部调用 
     * @param mList 
     */  
    public void changeData(List<String> mList) {  
        //这里用addAll也很重要,如果用this.list = mList,调用notifyDataSetChanged()无效  
        //notifyDataSetChanged()数据源发生改变的时候调用的,this.list = mList,list并没有发生改变  
        list.addAll(mList);  
        adapter.notifyDataSetChanged();  
    }  
      
      
    /** 
     * 回调接口.供外部调用 
     */  
    public interface OnPopupWindowClickListener{  
        /** 
         * 当点击PopupWindow的ListView 的item的时候调用此方法,用回调方法的好处就是降低耦合性 
         * @param position 位置 
         */  
        void onPopupWindowItemClick(int position);  
    }    
}  

用到了两个动画,在res文件夹下创建anim文件夹,里面创建两个动画xml
popupwindow_enter.xml

<?xml version="1.0" encoding="UTF-8"?>    
<set xmlns:android="http://schemas.android.com/apk/res/android">    
    <translate     
        android:fromXDelta="100%p"    
        android:toXDelta="0"    //这两行是從右邊進
        android:duration="500"/>    
</set>   

popupwindow_exit.xml

<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android">  
    <translate   
        android:fromXDelta="0"  
        android:toXDelta="100%p"  //这两行是往右邊消失
        android:duration="500"/>  
</set>  

在styles.xml里添加

 <style name="popupwindow_animation">  
        <item name="android:windowEnterAnimation">@anim/popupwindow_enter</item>  
        <item name="android:windowExitAnimation">@anim/popupwindow_exit</item>  
    </style>  

调用MyPopupWindow

public class PopupActivity extends AppcompatActivity {  
    MyPopupWindow mPopupWindow;  
    String [] items = {"刷新列表", "修改密码", "系统设置", "添加用户", "关于"};  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
        Button mButton = (Button) findViewById(R.id.button1);  
        mButton.setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View view) {  
                mPopupWindow.showAsDropDown(view);  
            }  
        });  
          
        mPopupWindow= new MyPopupWindow(this);  
        mPopupWindow.changeData(Arrays.asList(items));  
        mPopupWindow.setOnPopupWindowClickListener(new OnPopupWindowClickListener() {  
              
            @Override  
            public void onPopupWindowItemClick(int position) {  
                //需要实现的功能
                Toast.makeText(getApplication(), items[position], Toast.LENGTH_SHORT).show();  
            }  
        });  
    }  
  
  
}  

代码中的回调机制:

回调机制.png

注:

android:fromXDelta="0" android:toXDelta="-100%p" 往左邊消失
android:fromXDelta="-100%p" android:toXDelta="0" 從左邊進
android:fromXDelta="0" android:toXDelta="100%p" 往右邊消失
android:fromXDelta="100%p" android:toXDelta="0" 從右邊進

fromXDelta,fromYDelta 起始时X,Y座标,屏幕右下角的座标是X:320,Y:480
toXDelta, toYDelta 动画结束时X,Y的座标
interpolator 指定动画插入器
常见的有加速减速插入器 accelerate_decelerate_interpolator
加速插入器 accelerate_interpolator,
减速插入器 decelerate_interpolator。
fromXScale,fromYScale, 动画开始前X,Y的缩放,0.0为不显示, 1.0为正常大小
toXScale,toYScale, 动画最终缩放的倍数, 1.0为正常大小,大于1.0放大
pivotX, pivotY 动画起始位置,相对于屏幕的百分比,两个都为50%表示动画从屏幕中间开始
startOffset, 动画多次执行的间隔时间,如果只执行一次,执行前会暂停这段时间,单位毫秒 duration,一次动画效果消耗的时间,单位毫秒,值越小动画速度越快 repeatCount,动画重复的计数,动画将会执行该值+1次
repeatMode,动画重复的模式,reverse为反向,当第偶次执行时,动画方向会相反。
restart为重新执行,方向不变

参考:
PopupWindow的使用以及ArrayAdatper.notifyDataSetChanged()无效详解
Android-自定义PopupWindow

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容