一.全局弹窗
方式一:通过申请特殊权限来弹出全局弹窗
1.先在清单文件里面进行配置权限(兼容低版本):
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
2.动态申请权限(兼容高版本)
if (Build.VERSION.SDK_INT >= 23) {
//android6.0及以上需要去申请特殊权限
if (!Settings.canDrawOverlays(SecondActivity.this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(intent);
return;
} else {
AlertDialog alertDialog = new AlertDialog.Builder(getApplicationContext()).create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alertDialog.show();
}
} else {
//Android6.0以下,不用动态声明权限
AlertDialog alertDialog = new AlertDialog.Builder(getApplicationContext()).create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alertDialog.show();
}
也可以制作悬浮窗:
// 获取应用的Context
Context mContext = getApplicationContext();
// 获取WindowManager
WindowManager mWindowManager = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
View view = getLayoutInflater().from(mContext).inflate(R.layout.popupwindow, null);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
// 类型
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
// 设置flag
int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
params.flags = flags;
// 不设置这个弹出框的透明遮罩显示为黑色
params.format = PixelFormat.TRANSLUCENT;
// FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
// 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
// 不设置这个flag的话,home页的划屏会有问题
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.CENTER;
mWindowManager.addView(view, params);
方式二:创建一个样式为dialog的Activity然后弹出窗体.
1.设置activity的样式为Dialog的样子.
<style name="translucent" parent="Theme.AppCompat.Light.Dialog">
</style>
2.将activity的样式背景颜色设为半透明的即可.
<style name="translucent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@color/translucent_background</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<color name="translucent_background">#60000000</color>
二.弹窗动画效果。
步骤一:dialog_enter_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.0"
android:fromYScale="1.0"
android:toYScale="0.0"
android:pivotX="0%"
android:pivotY="100%"
android:fillAfter="false"
android:duration="400"/>
</set>
步骤二:dialog_exit_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="400"
android:fillAfter="false"
android:fromXScale="1.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="0%"
android:pivotY="100%"
android:toXScale="1.0"
android:toYScale="1.0"/>
</set>
步骤三:设置style
<style name="mystyle" parent="android:Animation">
<item name="@android:windowEnterAnimation">@anim/dialog_enter</item> //进入时的动画
<item name="@android:windowExitAnimation">@anim/dialog_exit</item> //退出时的动画
</style>
步骤四:初始化弹窗
AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
.setTitle("title").setMessage("message").create();
Window window = dialog.getWindow();
window.setGravity(Gravity.BOTTOM); //此处可以设置dialog显示的位置
window.setWindowAnimations(R.style.mystyle); //添加动画*/
dialog.show();
三.底部弹窗动画。
1.写好样式.弹出动画文件
<style name="BottomDialog" parent="@style/Base.V7.Theme.AppCompat.Light.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
<style name="BottomDialog.Animation" parent="Animation.AppCompat.Dialog">
<item name="android:windowEnterAnimation">@anim/translate_dialog_in</item>
<item name="android:windowExitAnimation">@anim/translate_dialog_out</item>
</style>
<!--translate_dialog_in-->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="0"
android:fromYDelta="100%"
android:toXDelta="0"
android:toYDelta="0">
</translate>
<!--translate_dialog_out-->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="100%">
</translate>
2弹出窗体.
Dialog bottomDialog = new Dialog(this, R.style.BottomDialog);
View contentView = LayoutInflater.from(this).inflate(R.layout.dialog_content_normal, null);
bottomDialog.setContentView(contentView);
ViewGroup.LayoutParams layoutParams = contentView.getLayoutParams();
layoutParams.width = getResources().getDisplayMetrics().widthPixels;
contentView.setLayoutParams(layoutParams);
bottomDialog.getWindow().setGravity(Gravity.BOTTOM);
bottomDialog.setCanceledOnTouchOutside(true);
bottomDialog.getWindow().setWindowAnimations(R.style.BottomDialog_Animation);
bottomDialog.show();
<!--带有间隙的dialog-->
Dialog bottomDialog = new Dialog(this, R.style.BottomDialog);
View contentView = LayoutInflater.from(this).inflate(R.layout.dialog_content_circle, null);
bottomDialog.setContentView(contentView);
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) contentView.getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels - DensityUtil.dp2px(this, 16f);
params.bottomMargin = DensityUtil.dp2px(this, 8f);
contentView.setLayoutParams(params);
bottomDialog.setCanceledOnTouchOutside(true);
bottomDialog.getWindow().setGravity(Gravity.BOTTOM);
bottomDialog.getWindow().setWindowAnimations(R.style.BottomDialog_Animation);
bottomDialog.show();
四.PopuWindow相关.
1 showAtLocation(相对于组件parent屏幕)
public void showAtLocation(View parent, int gravity, int x, int y)
1. parent可以为Activity中的任意一个View(最终的效果一样),会通过这个View找到其父Window,也就是Activity的Window。
2. gravity,默认为Gravity.NO_GRAVITY,等效于Gravity.LEFT | Gravity.TOP
3. x, y,边距。这里的x,y表示距离Window边缘的距离,方向由Gravity决定。例如:设置了Gravity.TOP,则y表示与Window上边缘的距离;而如果设置了Gravity.BOTTOM,则y表示与下边缘的距离。
4. 如果弹窗位置超出了Window的范围,会自动处理使其处于Window中
5. 相对于屏幕(左上角0,0),窗位置超出了Window的范围,会自动处理使其处于Window中,显示范围是顶部和底部
2 showAsDropDown(相对于组件)
public void showAsDropDown(View anchor, int xoff, int yoff)
1. 弹窗会显示在anchor控件的正下方。
2. 如果指定了xoff和yoff,则会在原有位置向右偏移xoff,向下偏移yoff。
3. 如果指定gravity为Gravity.RIGHT,则弹窗和控件右对齐;否则左对齐。注意,计算右对齐时使用了- PopupWindow的宽度,如果指定的宽度不是固定值,则计算会失效(可以从源码中看出来)。
4. 如果弹窗位置超出了Window的范围,会自动处理使其处于Window中。
5. 如果anchor可以滚动,则滚动过程中,PopupWindow可以自动更新位置,跟随anchor控件。
6. 相对于组件(左下角 0,屏幕高度)
总结: showAtLocation 和showAsDropDown主要区别于显示位置相对于屏幕还是组件