我看网上对于PopupWindow的介绍非常的少就自己写一篇, 本文基本上分析了PopupWindow的所有方法.
PopupWindow是对于屏幕添加一个显示区域, 由于对位置和内容都非常自由所以常常在开发中用到.
看完后建议也看下PopupMenu详细使用
创建
一般用的构造方法.
1
2
3
4
5
6
7
8
9
10
11
|
PopupWindow ()
PopupWindow (View contentView)
PopupWindow (
int width,
int height)
PopupWindow (View contentView,
int width,
int height,
boolean focusable)
|
通过上下文创建PopupWindow, 创建后默认有一个透明的背景.默认宽高(0,0), 没有内容和焦点的PopupWindow. 具体作用我也不知道, 估计是写自定义控件的吧. 但是PopupWindow并没有继承View.一般不使用该构造.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
PopupWindow (Context context)
PopupWindow (Context context,
AttributeSet attrs)
PopupWindow (Context context,
AttributeSet attrs,
int defStyleAttr)
PopupWindow (Context context,
AttributeSet attrs,
int defStyleAttr,
int defStyleRes)
|
创建PopuWindow必要的三个条件:
1
2
3
|
void setHeight (int height)
void
setWidth
(int width)
void
setContentView
(View contentView)
|
缺少一个就无法显示.
前面提到PopupWindow需要设置宽高, 那如果想用布局中的宽高怎么办呢?
可以用到LayoutParams.WRAP_CONTENT
包裹布局. 布局多大就显示多大的PopupWindow
1
|
PopupWindow popupWindow =
new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
true);
|
显示
显示PopupWindow可以分为两种方式:
- 附着某个控件
showAsDropDown
- 设置屏幕坐标
showAtLocation
相对于当前控件
默认是PopupWindow的左上角对其控件的左下角
或者设置Gravity.RIGHT
, PopupWindow的右上角对齐控件的右下角
不存在Gravity.TOP
或Gravity.BOTTOM
效果
1
2
3
4
5
6
7
8
9
10
11
|
void showAsDropDown (View anchor)
void
showAsDropDown
(View anchor,
int xoff, // 以控件左下角为原点的偏移坐标
int yoff)
void
showAsDropDown
(View anchor,
int xoff,
int yoff,
int gravity)
|
相对于当前窗口
当前窗口的任意位置(不包括状态栏)
1
2
3
4
|
void showAtLocation (View parent, // 该属性只要是屏幕上任意控件对象即可
int gravity, // 屏幕位置
int x, // 偏移坐标
int y)
|
parent:该属性只要是当前任意控件对象即可(View和ViewGroup都行), 官方文档介绍该对象参数主要是为了得到该对象的getWindowToken()
方法.
需要注意的是多次调用show方法, 只会执行第一句
1
2
3
4
|
mPopupWindow.showAtLocation(popupwindow, Gravity.TOP,
100,
0);
mPopupWindow.showAtLocation(popupwindow, Gravity.LEFT,
100,
0);
mPopupWindow.showAtLocation(popupwindow, Gravity.RIGHT,
100,
0);
mPopupWindow.showAtLocation(popupwindow, Gravity.BOTTOM,
100,
0);
|
该方法只能在show
后才能执行否则crash
状态
可被点击
1
2
|
boolean isTouchable ()
void
setTouchable
(boolean touchable)
|
多点触控
1
2
|
void setSplitTouchEnabled (boolean enabled)
boolean
isSplitTouchEnabled
()
|
忽略CheekPress事件
当物体触摸在屏幕上的尺寸超过手指尺寸范围, 将被判定为CheekPress事件(脸颊点击).
1
|
void setIgnoreCheekPress ()
|
弹窗外部被点击
如果为true点击PopupWindow外部区域可以取消PopupWindow
1
2
|
void setOutsideTouchable (boolean touchable)
boolean
isOutsideTouchable
()
|
解决NavigationBar重叠
这是Android5.0(API22)后添加的方法, 默认为true. 为true时将不会与导航栏重叠.
1
|
void setAttachedInDecor (boolean enabled)
|
可获取焦点
一般控件都不需要焦点. 但是输入框EditText需要先获取焦点才能输入. 最重要的是当PopupWindow可获取焦点时按下手机返回键将不会销毁当前Activity而是关闭当前PopupWindow. 所以我们一般还是设置为true. 更加符合用户操作逻辑. 该方法为true时同时拥有setOutsideTouchable(true)
的作用.
1
2
|
void setFocusable (boolean focusable)
boolean
isFocusable
()
|
设置背景
1
2
|
void setBackgroundDrawable (Drawable background)
Drawable
getBackground
()
|
阴影
该方法我测试无效
1
2
|
void setElevation (float elevation)
float
getElevation
()
|
附着View位置
该方法只在showAsDropDown()
方法执行后才有效. 可以判断PopupWindow和附着View anchor谁的Y轴坐标小.
1
|
boolean isAboveAnchor ()
|
遮盖附着View
1
2
|
void setOverlapAnchor (boolean overlapAnchor)
boolean
getOverlapAnchor
()
|
可以从图中看到对齐方式从View anchor的左下角变成了左上角了.
该方法在API23后被废弃, 由setWidth(int) 和 setHeight(int)替代
1
2
|
void setWindowLayoutMode (int widthSpec,
int heightSpec)
|
窗口裁剪
PopupWindow默认是不会超出屏幕边界的. 但是如果该方法为false时会采用精准位置, 能超出屏幕范围.
1
2
|
void setClippingEnabled (boolean enabled)
boolean
isClippingEnabled
()
|
演示超出屏幕:
1
|
mPopupWindow.showAtLocation(mBtnOpenPopup, Gravity.BOTTOM,
0, -
30);
|
动画效果
设置动画
可以设置popupWindow的显示和隐藏动画
1
2
3
|
void setAnimationStyle (int animationStyle)
int
getAnimationStyle
()
|
可以看到方法是传入一个Style的样式id
示例:
1
2
3
4
|
<style name="popupwindow_anim_style">
<item name="android:windowEnterAnimation">@anim/dialog_bottom_enter
</item>
<item name="android:windowExitAnimation">@anim/dialog_bottom_exit
</item>
</style>
|
分别由两个属性组成. 两个属性各代表一个anim动画文件.
进入和退出动画
这是在Android6.0(API 23)后加入的方法. 配合Material Design的转场动画使用.
进入动画
1
2
|
void setEnterTransition (Transition enterTransition)
Transition
getEnterTransition
()
|
退出动画
1
2
|
void setExitTransition (Transition exitTransition)
Transition
getExitTransition
()
|
获取
获取最大高度
这是相当于传入的View对象可显示的最大高度. 即PopupWindow使用showAsDropDown()
能够显示的最大高度
1
2
3
4
5
6
7
8
|
int getMaxAvailableHeight (View anchor)
int
getMaxAvailableHeight
(View anchor,
int yOffset)
int
getMaxAvailableHeight
(View anchor, // api24增加的方法, 由于我手上没有7.0设备就不说了.
int yOffset,
boolean ignoreBottomDecorations)
|
输入模式
针对PopupWindow中包含EditText控件.
输入模式
我使用该方法的三种模式我感觉并没有什么卵用
1
2
|
void setInputMethodMode (int mode)
int
getInputMethodMode
()
|
支持三种模式
- INPUT_METHOD_FROM_FOCUSABLE 根据可否获取焦点判断是否可输入. 感觉鸡肋
- INPUT_METHOD_NEEDED 允许输入
- INPUT_METHOD_NOT_NEEDED 不允许输入
软键盘模式
1
2
|
void setSoftInputMode (int mode)
int
getSoftInputMode
()
|
softInputMode
包含九种取值, 可组合使用,分为两类:
显示状态模式
- SOFT_INPUT_STATE_UNSPECIFIED 默认模式
- SOFT_INPUT_STATE_HIDDEN
- SOFT_INPUT_STATE_ALWAYS_HIDDEN 总是隐藏
- SOFT_INPUT_STATE_UNCHANGED
- SOFT_INPUT_STATE_VISIBLE
- SOFT_INPUT_STATE_ALWAYS_VISIBLE 自动弹出软键盘
调整模式
- SOFT_INPUT_ADJUST_UNSPECIFIED 默认模式
- SOFT_INPUT_ADJUST_RESIZE 软键盘弹出后PopupWindow会自动调整坐标,不被遮挡
- SOFT_INPUT_ADJUST_PAN
监听事件
隐藏事件监听
即PopupWindow执行dismiss()
后回调的方法.
1
|
void setOnDismissListener (PopupWindow.OnDismissListener onDismissListener)
|
触摸事件拦截
1
|
void setTouchInterceptor (View.OnTouchListener l)
|
更新
以下的更新PopupWindow都必须在PopupWindow处于以及被显示的状态下才行. 且PopupWindow的宽高设置都必须大于等于0. 如果想忽略PopupWindow的宽高设置就设为-1.
更新状态
该方法不能更新PopupWindow的宽高, 只能更新PopupWindow的状态. 例如更新Focusable
和OutsideTouchable
更新尺寸
上面说过update()
不能更新PopupWindow的宽高, 但是提供更新宽高的update方法
1
2
|
void update (int width, // 更新PopupWindow的宽高
int height)
|
更新显示位置
该方法是相当于重新showAsDropDown
, 所以这是相对于控件的位置更新
1
2
3
4
5
6
7
8
9
|
void update (View anchor, // 更新显示控件的位置
int width,
int height)
void
update
(View anchor,
int xoff, // 相对于控件的偏移值
int yoff,
int width,
int height)
|
相对位置更新
是相对于当前的位置进行偏移. 不同的显示位置对于的相对原点也不同.
showAsDropDown
的相对原点是整个屏幕左上角, 包括状态栏. 所以由于包括状态栏所以坐标偏移的时候一定要y轴偏移大于60超出状态栏的高度. 否则因为遮挡状态栏导致PopupWindow无法显示.
1
|
mPopupWindow.update(
50,
60, -
1,-
1);
|
showAtLocation
的相对原点是自身位置.
1
2
3
4
5
6
7
8
9
10
|
void update (int x, // 坐标偏移
int y,
int width, // PopupWindow宽高
int height)
void
update
(int x,
int y,
int width,
int height,
boolean force)
|