1)通过style实现弹出与消失的动画
2)Window实现背景在弹框显示消失时的明暗效果
3)showAtLocation控制弹框位置
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/layout_main"
android:gravity="center_horizontal"
tools:context="com.bpj.popwindow.MainActivity">
<Button
android:layout_marginTop="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="popup"
android:onClick="popup"
/>
<Button
android:layout_marginTop="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dismiss"
android:onClick="dismiss"
/>
LinearLayout>
popu.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="200dp"
android:layout_height="60dp"
android:background="@color/colorPrimary"
>
<TextView
android:layout_width="wrap_content"
android:text="111"
android:layout_height="60dp" />
LinearLayout>
anim文件夹下:
menu_bottombar_in.xml显示动画
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromYDelta="100.0%"
android:toYDelta="0.0" />
set>
menu_bottombar_out.xml消失动画
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromYDelta="0.0"
android:toYDelta="100%" />
set>
style中:
public class MainActivity extends AppCompatActivity {
private PopupWindow popupWindow;
private WindowManager.LayoutParams params;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
params = getWindow().getAttributes();
}
/**
* 这里popupWindow用的是showAtLocation而不是showAsDropDown
* popupWindow.isShowing会一直返回false,所以要重新定义一个变量
* 要注意setOutsideTouchable的干扰
*/
private boolean mIsShowing = false;
public void popup(View view){
if(popupWindow == null){
initPopup();
}
if(!mIsShowing){
params.alpha= 0.3f;
getWindow().setAttributes(params);
popupWindow.showAtLocation(findViewById(R.id.layout_main),Gravity.BOTTOM,0,0);
mIsShowing = true;
}
}
private void initPopup() {
View pop = View.inflate(this, R.layout.popu, null);
popupWindow = new PopupWindow(pop, ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setTouchable(true);
popupWindow.setOutsideTouchable(false);
popupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(), (Bitmap) null));
popupWindow.setAnimationStyle(R.style.anim_menu_bottombar);
mIsShowing = false;
}
public void dismiss(View view){
if(popupWindow != null &&mIsShowing){
popupWindow.dismiss();
mIsShowing = false;
params.alpha= 1f;
getWindow().setAttributes(params);
}
}
}
产生原因:窗体泄漏,每一个Activity都有个WindowManager窗体管理器,同样,构建在某个Activity之上的对话框、PopupWindow也有相应的WindowManager窗体管理器。因为对话框、PopupWindown不能脱离Activity而单独存在着,所以当某个Dialog或者某个PopupWindow正在显示的时候我们去finish()了承载该Dialog(或PopupWindow)的Activity时,就会抛Window Leaked异常了,因为这个Dialog(或PopupWindow)的WindowManager已经没有谁可以附属了,所以它窗体管理器已经泄漏了。Activity 中create 一个Dialog,若你先关闭Dialog再关闭Activity就是正常的,若你先关闭Activity再关闭Dialog就会报错这个android.view.WindowLeaked错误了。
解决方法:关闭(finish)某个Activity前,要确保附属在上面的Dialog或PopupWindow已经关闭(dismiss)了。也可在OnCreateDialog()中创建Dialog,让系统去管理对话框
popupWindow用的是showAtLocation而不是showAsDropDown
* popupWindow.isShowing会一直返回false,所以要重新定义一个变量
* 要注意setOutsideTouchable的干扰,setOutsideTouchable设置为false
重新该方法:
@Override
public void showAsDropDown(View anchorView, int xoff, int yoff, int gravity) {
if (getHeight() == ViewGroup.LayoutParams.MATCH_PARENT &&
Build.VERSION.SDK_INT >= 24) { // Build.VERSION_CODES.N
int[] a = new int[2];
anchorView.getLocationInWindow(a);
int yoffInWindow = a[1] + anchorView.getHeight() + yoff;
setHeight(getPopMatchHeight(anchorView.getContext(), yoffInWindow));
showAtLocation(anchorView, gravity, xoff, yoffInWindow);
} else {
super.showAsDropDown(anchorView, xoff, yoff, gravity);
}
}
private int getPopMatchHeight(Context context, int yoffInWindow) {
return context.getResources().getDisplayMetrics().heightPixels - yoffInWindow;
}