Android弹窗PopupWindow详解

我看网上对于PopupWindow的介绍非常的少就自己写一篇, 本文基本上分析了PopupWindow的所有方法.

PopupWindow是对于屏幕添加一个显示区域, 由于对位置和内容都非常自由所以常常在开发中用到.

看完后建议也看下PopupMenu详细使用

创建

一般用的构造方法.

 

1

2

3

4

5

6

7

8

9

10

11

 

PopupWindow () // 创建一个空的PopupWindow

PopupWindow (View contentView)

PopupWindow (int width,

int height)

PopupWindow (View contentView, // PopupWindow的内容View, 相当于setContentView

int width, // 宽, 相当于setwidth()

int height, // 高, 相当于setHeight

boolean focusable) // 是否可获取焦点, 相当于setFocusable()

通过上下文创建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) // 因为PopupWindow没有默认布局所以必须指定宽高

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可以分为两种方式:

  1. 附着某个控件showAsDropDown
  2. 设置屏幕坐标showAtLocation

相对于当前控件

默认是PopupWindow的左上角对其控件的左下角

或者设置Gravity.RIGHT, PopupWindow的右上角对齐控件的右下角

不存在Gravity.TOPGravity.BOTTOM效果

 

1

2

3

4

5

6

7

8

9

10

11

 

void showAsDropDown (View anchor) // 弹窗显示在anchor控件左下方

void showAsDropDown (View anchor,

int xoff, // 以控件左下角为原点的偏移坐标

int yoff)

void showAsDropDown (View anchor,

int xoff,

int yoff,

int gravity)

// 弹窗显示在控件的左下方还是右下方, 参数Gravity.RIGHT/Gravity.LEFT. 默认是左下方

相对于当前窗口

当前窗口的任意位置(不包括状态栏)

 

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);

隐藏PopupWindow

该方法只能在show后才能执行否则crash

 

1

 

void dismiss ()

状态

可被点击

 

1

2

 

boolean isTouchable () // 判断是否可被点击

void setTouchable (boolean touchable) // 设置是否可被点击

多点触控

 

1

2

 

void setSplitTouchEnabled (boolean enabled)

boolean isSplitTouchEnabled ()

忽略CheekPress事件

当物体触摸在屏幕上的尺寸超过手指尺寸范围, 将被判定为CheekPress事件(脸颊点击).

 

1

 

void setIgnoreCheekPress () // 默认为false, 即不忽略

弹窗外部被点击

如果为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的左下角变成了左上角了.

设置PopupWindow宽高

该方法在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) // 控件Y轴偏移后可显示的最大高度

int getMaxAvailableHeight (View anchor, // api24增加的方法, 由于我手上没有7.0设备就不说了.

int yOffset,

boolean ignoreBottomDecorations)

输入模式

针对PopupWindow中包含EditText控件.

输入模式

我使用该方法的三种模式我感觉并没有什么卵用

 

1

2

 

void setInputMethodMode (int mode)

int getInputMethodMode ()

支持三种模式

  1. INPUT_METHOD_FROM_FOCUSABLE 根据可否获取焦点判断是否可输入. 感觉鸡肋
  2. INPUT_METHOD_NEEDED 允许输入
  3. INPUT_METHOD_NOT_NEEDED 不允许输入

软键盘模式

 

1

2

 

void setSoftInputMode (int mode) // mode为WindowManager.LayoutParams的softInputMode常量

int getSoftInputMode ()

softInputMode

包含九种取值, 可组合使用,分为两类:

显示状态模式

  1. SOFT_INPUT_STATE_UNSPECIFIED 默认模式
  2. SOFT_INPUT_STATE_HIDDEN
  3. SOFT_INPUT_STATE_ALWAYS_HIDDEN 总是隐藏
  4. SOFT_INPUT_STATE_UNCHANGED
  5. SOFT_INPUT_STATE_VISIBLE
  6. SOFT_INPUT_STATE_ALWAYS_VISIBLE 自动弹出软键盘

调整模式

  1. SOFT_INPUT_ADJUST_UNSPECIFIED 默认模式
  2. SOFT_INPUT_ADJUST_RESIZE 软键盘弹出后PopupWindow会自动调整坐标,不被遮挡
  3. 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的状态. 例如更新FocusableOutsideTouchable

 

1

 

void update ()

更新尺寸

上面说过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); // x轴偏移50

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) // 可获取焦点

popupWindow弹窗外区域设置阴影

透明度50% 用7F表示。

1.在创建popupWindow时:

显示阴影 WindowManager.LayoutParams lp=getActivity().getWindow().getAttributes();         lp.alpha=0.7f;         getActivity().getWindow().setAttributes(lp);

2.在popupWindow dismiss时:

去掉阴影 WindowManager.LayoutParams lp=getActivity().getWindow().getAttributes();                 lp.alpha=1f;                 getActivity().getWindow().setAttributes(lp); 

 

PopupWindow效果篇

实现的方法是:

private void show(){
View popLayout = LayoutInflater.from(this).inflate(R.layout.layout_pop_up_window,null);
ImageView ivPop = popLayout.findViewById(R.id.iv_pop);
ivPop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "123456789", Toast.LENGTH_SHORT).show();
}
});
PopupWindow popupWindow = new PopupWindow(popLayout, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setTouchable(true);
popupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return false;
}
});
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ColorDrawable(0));
popupWindow.setAnimationStyle(R.style.pop_anim);
popupWindow.showAtLocation(btnShow, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
}

在values中的style文件中添加样式:

<style name="pop_anim" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pop_enter_anim</item>
<item name="android:windowExitAnimation">@anim/pop_exit_anim</item>
</style>

在res文件夹下,新建anim文件夹,新建两个文件:

pop_enter_anim:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromYDelta="100%p"
android:toYDelta="0" />
<alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

pop_exit_anim:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="1000"
android:fromYDelta="0"
android:toYDelta="50%p" />
<alpha
android:duration="1000"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

# Anadroid UI

猜你喜欢

转载自blog.csdn.net/wusj3/article/details/82838367