示例源码:
package com.example.jnotification;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
public class CustomCreateNotification extends Activity {
private View view;
private WindowManager wm;
private boolean showWm = true;// 默认是应该显示悬浮通知栏
private WindowManager.LayoutParams params;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(CustomCreateNotification.this)) {
Intent intent = new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 88);
} else {
createFloatView();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 88) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
createFloatView();
}
}
}
private void createFloatView( ) {
wm = (WindowManager) getApplicationContext().getSystemService(
Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams();
/*//这里需要着重说明的是LayoutParam里的type变量。这个变量是用来指定窗口类型的。
//在设置这个变量时,需要注意一个坑,那就是需要对不同版本的Android系统进行适配。
//在Android 8.0之前,悬浮窗口设置可以为TYPE_PHONE,这种类型是用于提供用户交互操作的非应用窗口。
//而Android 8.0对系统和API行为做了修改,包括使用SYSTEM_ALERT_WINDOW权限的应用无法再使用以下窗口类型来在其他应用和窗口上方显示提醒窗口
// TYPE_PHONE
///TYPE_PRIORITY_PHONE
//TYPE_SYSTEM_ALERT
// TYPE_SYSTEM_OVERLAY
//TYPE_SYSTEM_ERROR
//如果需要实现在其他应用和窗口上方显示提醒窗口,那么必须该为TYPE_APPLICATION_OVERLAY的新类型。
//如果在Android 8.0以上版本仍然使用TYPE_PHONE类型的悬浮窗口,则会出现如下异常信息:*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
}
params.format = PixelFormat.TRANSPARENT;
//设置必须触摸通知栏才可以关掉
params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
// 设置通知栏的长和宽
params.width = wm.getDefaultDisplay().getWidth();
params.height = 200;
params.gravity =Gravity.TOP;
view = LayoutInflater.from(this).inflate(R.layout.notification, null);
//在这里你可以解析你的自定义的布局成一个View
if (showWm){
wm.addView(view, params);
showWm = false;
}else {
wm.updateViewLayout(view,params);
}
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
wm.removeViewImmediate(view);//触摸到悬浮窗口区域即消失窗口
view = null;
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
});
}
}
备注【代码一】:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
}
当你在 AndroidMainfest.xml文件中声明了下面权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
且也动态申请了权限 ,但运行应用仍出现异常,是因为没在在实现中加入上面的【代码一】源码,
引申阅读: