我们使用AlertDialog的时候一般不会去改变它的位置(默认居中),如果我们想去指定一个在任意位置显示的弹窗,可以使用Popup Window,它对于位置的控制会更加灵活
点击显示一个底部弹窗按钮,出现下图效果,点击弹窗外界,关闭弹窗
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".popupwindow.PopupWindowActivity">
<Button
android:id="@+id/btn_show_bottom_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="显示一个底部弹窗"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:padding="16dp">
<Button
android:id="@+id/btn_show_simple"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="测试按钮1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_show_dialog_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="测试按钮2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_show_simple" />
<Button
android:id="@+id/btn_show_auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="测试按钮3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_show_dialog_fragment" />
</androidx.constraintlayout.widget.ConstraintLayout>
public class PopupWindowActivity extends AppCompatActivity {
private PopupWindow popupWindow;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup_window);
ConstraintLayout parent = findViewById(R.id.main);
findViewById(R.id.btn_show_bottom_menu).setOnClickListener(view ->{
//显示在哪个根布局,位置,xy坐标
popupWindow.showAtLocation(parent, Gravity.BOTTOM,0,0);
setBackgroundAlpha(0.3f);
});
createBottomPopupWindow();
}
private void createBottomPopupWindow(){
View view = getLayoutInflater().inflate(R.layout.layout_bottom_menu_popupwindow, null);
popupWindow = new PopupWindow(view,
ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setOutsideTouchable(true);
//如果弹窗消失,就把透明度修改回来
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
setBackgroundAlpha(1.0f);
}
});
}
private void setBackgroundAlpha(float f){
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.alpha = f;
getWindow().setAttributes(layoutParams);
}
}
PopupWindow弹窗,可以让我们对于弹窗位置的控制会更加灵活,
构造方法的重载,最常用的是最后一种
两种写法创建PopupWindow,合在一起,分开都可以
View view = getLayoutInflater().inflate(R.layout.layout_bottom_menu_popupwindow, null);
popupWindow = new PopupWindow(view,
ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
这个方法就是把PopupWindow显示到当前某个布局当中;
xy偏移量;x正-整体往右移动,y正-整体往下移动;
偏移后不允许超出屏幕,所以很多时候偏移量是否生效,取决于Gravity以及当前弹窗布局的大小:比如当前布局宽度已经被设定为match_parent,所以x偏移量不会生效
ConstraintLayout parent = findViewById(R.id.main);
findViewById(R.id.btn_show_bottom_menu).setOnClickListener(view ->{
//显示在哪个根布局,位置,xy坐标
popupWindow.showAtLocation(parent, Gravity.BOTTOM,0,0);
setBackgroundAlpha(0.3f);
});
createBottomPopupWindow();
PopupWindow根布局的高度不要写成match_content(匹配父布局),PopupWindow
的设计初衷是作为 “轻量级悬浮弹窗”,而非全屏视图。将其根布局高度设为match_parent
会违背这一特性,导致显示异常、交互受阻等问题。使用**wrap_content
**或精确指定高度,才能让PopupWindow
的行为符合预期,避免隐藏的兼容性与用户体验问题。
包不要导错了,用androidx下的包
给根布局背景色设置为白色即可
效果对比
setOutsideTouchable
点击外部区域,弹窗允许关闭;源码中默认值为false,更改为true
设置弹窗消失监听器
针对PopupWindow,一般来说我们是不用去针对空余位置设置半透明的,但是有些商业需求比较奇葩,
思路:当弹窗时,给空余区域加一个透明的样式;当关闭的时候,再把这个样式给关闭掉
Alpha透明度之前学过的,包括如何获取它,修改它,再把修改后的参数设置回去,这里用方法包装了一下
PopupWindow的创建方式,怎么修改它的透明度,弹窗的监听器怎么样