概述
A popup window that can be used to display an arbitrary view. The popup window is a floating container that appears on top of the current activity.
一个弹出窗口控件,可以用来显示任意View,而且会浮动在当前activity的顶部
常用构造方法
一下仅列出本人认为常用的构造方法,全部构造方法(9个….)请查看官方文档。
- public PopupWindow (Context context)
- public PopupWindow(View contentView, int width, int height)
- public PopupWindow(View contentView)
- public PopupWindow(View contentView, int width, int height, boolean focusable)
contentView是PopupWindow显示的View,focusable是否显示焦点
常用方法
介绍几个用得较多的一些方法,其他的可自行查阅文档:
Code
效果图
res\anim\anim_pop.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha="0" android:toAlpha="1" android:duration="2000"> </alpha> </set>
res\layout\item_popup.xml
android:background 是一张.9图片
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/ic_pop_bg" android:orientation="vertical"> <TextView android:id="@+id/textview1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:text="选项一选项一选项一选项一选项一选项一" android:textSize="18sp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#98FB98" /> <TextView android:id="@+id/textview2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:text="选项二选项二选项二选项二选项二选项二" android:textSize="18sp" /> </LinearLayout>
PopupWindowAct.java
package com.turing.base.activity.popupWindowDemo; import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; import com.turing.base.R; public class PopupWindowAct extends AppCompatActivity { private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_popup_window); mContext = PopupWindowAct.this; } public void showPopupWindow(View view){ initPopWindow(view); } private void initPopWindow(View v) { // 将自定义布局转换为View View view = LayoutInflater.from(mContext).inflate(R.layout.item_popup, null, false); TextView tv1 = (TextView) view.findViewById(R.id.textview1); TextView tv2 = (TextView) view.findViewById(R.id.textview2); //1.构造一个PopupWindow,参数依次是加载的View,宽高 final PopupWindow popWindow = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); //设置加载动画 popWindow.setAnimationStyle(R.anim.anim_pop); //这些为了点击非PopupWindow区域,PopupWindow会消失的,如果没有下面的 //代码的话,你会发现,当你把PopupWindow显示出来了,无论你按多少次后退键 //PopupWindow并不会关闭,而且退不出程序,加上下述代码可以解决这个问题 popWindow.setTouchable(true); popWindow.setTouchInterceptor(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // 这里如果返回true的话,touch事件将被拦截 // 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss return false; } }); //要为popWindow设置一个背景才有效 popWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); //设置popupWindow显示的位置,参数依次是参照View,x轴的偏移量,y轴的偏移量 popWindow.showAsDropDown(v, 50, 0); //设置popupWindow里的按钮的事件 tv1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(PopupWindowAct.this, "你点击了选项一~", Toast.LENGTH_SHORT).show(); } }); tv2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(PopupWindowAct.this, "你点击了选项二~", Toast.LENGTH_SHORT).show(); popWindow.dismiss(); } }); } }
其他
PopUpWindow的焦点:
setFocusable设置PopupWindow的焦点,一般资料对此的解释都是:是否让Popupwindow可以点击但是这揭示了本质却与直观现象不符。实际上,
如果:
setFocusable(true);
则PopUpWindow本身可以看作一个类似于模态对话框的东西(但有区别),PopupWindow弹出后,所有的触屏和物理按键都有PopupWindows处理。其他任何事件的响应都必须发生在PopupWindow消失之后, (home 等系统层面的事件除外)。比如这样一个PopupWindow出现的时候,按back键首先是让PopupWindow消失,第二次按才是退出activity,准确的说是想退出activity你得首先让PopupWindow消失,因为不并是任何情况下按back PopupWindow都会消失,必须在PopupWindow设置了背景的情况下 。
如果PopupWindow中有Editor的话,focusable要为true。
而setFocusable(false);
则PopUpWindow只是一个浮现在当前界面上的view而已,不影响当前界面的任何操作。
是一个“没有存在感”的东西。
一般情况下setFocusable(true);
点击空白处的时候让PopupWindow消失
关于PopupWindow最搞笑的地方是setOutsideTouchable方法,原本以为如果你setOutsideTouchable(true)则点击PopupWindow之外的地方PopupWindow会消失,其实这玩意儿好像一点用都没有。
要让点击PopupWindow之外的地方PopupWindow消失你需要调用setBackgroundDrawable(new BitmapDrawable());
设置背景,为了不影响样式,这个背景是空的。还可以这样写,觉得这样要保险些:
setBackgroundDrawable(new ColorDrawable(0x00000000));
背景不为空但是完全透明。如此设置才能让PopupWindow在点击back的时候消失。
如果有背景,则会在contentView外面包一层PopupViewContainer之后作为mPopupView,如果没有背景,则直接用contentView作为mPopupView。
而这个PopupViewContainer是一个内部私有类,它继承了FrameLayout,在其中重写了Key和Touch事件的分发处理。
弹窗不消失,但是事件向下传递
设置了PopupWindow的background,点击Back键或者点击弹窗的外部区域,弹窗就会dismiss.
相反,如果不设置PopupWindow的background,那么点击back键和点击弹窗的外部区域,弹窗是不会消失的.
那么,如果我想要一个效果,点击外部区域,弹窗不消失,但是点击事件会向下面的activity传递,比如下面是一个WebView,我想点击里面的链接等.
研究了半天,说是要给Window设置一个Flag,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
看了源码,这个Flag的设置与否是由一个叫mNotTouchModal的字段控制,但是设置该字段的set方法被标记为@hide。
所以要通过反射的方法调用:
/** * Set whether this window is touch modal or if outside touches will be sent * to * other windows behind it. * */ public static void setPopupWindowTouchModal(PopupWindow popupWindow, boolean touchModal) { if (null == popupWindow) { return; } Method method; try { method = PopupWindow.class.getDeclaredMethod("setTouchModal", boolean.class); method.setAccessible(true); method.invoke(popupWindow, touchModal); } catch (Exception e) { e.printStackTrace(); } }
然后在程序中:
setPopupWindowTouchModal(popupWindow, false);
该popupWindow外部的事件就可以传递给下面的Activity了。