效果图
thanks
首先介绍一下常见的WindowManager.LayoutParams常量属性
layoutParams.flag
int类型 常量介绍 FLAGS_CHANGED 用于表示flags发生了变化 FLAG_ALLOW_LOCK_WHILE_SCREEN_ON 当该window对用户可见的时候,允许锁屏。 FLAG_BLUR_BEHIND 让该window后所有东西都模糊(blur) FLAG_DIM_BEHIND 让该window后所有的东西都成暗淡(dim) FLAG_DITHER 开启抖动(dithering) FLAG_FORCE_NOT_FULLSCREEN 恢复window非全屏显示 FLAG_FULLSCREEN 让window进行全屏显示 FLAG_KEEP_SCREEN_ON 当该window对用户可见时,让设备屏幕处于高亮(bright)状态。 FLAG_LAYOUT_IN_SCREEN 让window占满整个手机屏幕,不留任何边界(border) FLAG_LAYOUT_NO_LIMITS window大小不再不受手机屏幕大小限制,即window可能超出屏幕之外,这时部分内容在屏幕之外 FLAG_NOT_FOCUSABLE 让window不能获得焦点,这样用户快就不能向该window发送按键事件及按钮事件 FLAG_NOT_TOUCHABLE 让该window不接受触摸屏事件 FLAG_NOT_TOUCH_MODAL 即使在该window在可获得焦点情况下,仍然把该window之外的任何event发送到该window之后的其他window. FLAG_SECURE 当该window在进行显示的时候,不允许截屏。 FLAG_SHOW_WALLPAPER 在该window后显示系统的墙纸(wallpaper) FLAG_SHOW_WHEN_LOCKED 当锁屏的时候,显示该window. FLAG_TOUCHABLE_WHEN_WAKING 当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到到事件 FLAG_TURN_SCREEN_ON 当然window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕。 FLAG_WATCH_OUTSIDE_TOUCH 如果你设置了该flag,那么在你FLAG_NOT_TOUNCH_MODAL的情况下,即使触摸屏事件发送在该window之外,其事件被发送到了后面的window,那么该window仍然将以MotionEvent.ACTION_OUTSIDE形式收到该触摸屏事件
layoutParams.type
类型 int 属性介绍 TYPE_APPLICATION 普通的应用程序window,token必须设置为Activity的token,以指出该窗口属谁 TYPE_APPLICATION_ATTACHED_DIALOG 对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。 TYPE_APPLICATION_MEDIA 媒体窗口,例如视频。显示于宿主窗口下层。 TYPE_APPLICATION_PANEL 面板窗口,显示于宿主窗口上层 TYPE_APPLICATION_STARTING 用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。它用于让系统显示些信息,直到应用程序可以开启自己的窗口 TYPE_APPLICATION_SUB_PANEL 应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上) TYPE_BASE_APPLICATION 所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。 TYPE_INPUT_METHOD 内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖 TYPE_INPUT_METHOD_DIALOG 内部输入法对话框,显示于当前输入法窗口之上 TYPE_KEYGUARD 锁屏窗口 TYPE_KEYGUARD_DIALOG 锁屏时显示的对话框 TYPE_PHONE 电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。 TYPE_PRIORITY_PHONE 电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。 TYPE_SEARCH_BAR 搜索栏。只能有一个搜索栏;它位于屏幕上方。 TYPE_STATUS_BAR 状态栏类型的window。只能有一个状态栏window;它位于屏幕顶端,其他窗口都位于它下方。 TYPE_STATUS_BAR_PANEL 状态栏的滑动面板 TYPE_SYSTEM_ALERT 系统提示window,比如电池低的警告。它总是出现在应用程序窗口之上。 TYPE_SYSTEM_DIALOG 系统对话框。(例如音量调节框) TYPE_SYSTEM_ERROR 系统内部错误提示,显示于所有内容之上 TYPE_SYSTEM_OVERLAY 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。 TYPE_TOAST toast类型的window TYPE_WALLPAPER 用于墙纸的window
桌面浮窗权限申请
<usespermission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
此 权限6.0以上在清单文件注册没有效果,测试一下,就是动态申请权限也不能申请成功,只能用户手动开启,开启方法
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 10);
}
}
设置弹窗
private void showWindow() {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.width = 200;
layoutParams.height = 200;
layoutParams.gravity = Gravity.CENTER_VERTICAL;
layoutParams.format = PixelFormat.TRANSPARENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
layoutParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
view = View.inflate(MainActivity.this, R.layout.window_view, null);
TextView textView= (TextView) view;
textView.setText("自定义弹窗");
manager.addView(view, layoutParams);
view.setOnTouchListener(new View.OnTouchListener() {//可以根据TouchView逻辑设置窗体跟着手指移动
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
}
移除弹窗
windowManager.removeView(view)
自定义跟着手指移动的View
package cn.evun.snakebardemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
/**
*/
public class TouchView extends TextView {
private int downX;
private int downY;
private boolean isMove;
//屏幕密度
private float density = getResources().getDisplayMetrics().density;
public TouchView(Context context) {
super(context, null);
}
public TouchView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TouchView);
isMove = typedArray.getBoolean(R.styleable.TouchView_isMove, true);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//相对于控件左边缘的距离
downX = (int) event.getRawX();
downY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
int moveY = (int) event.getRawY();
int dx = moveX - downX;
int dy = moveY - downY;
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = layoutParams.leftMargin + (int) (dx * density);
layoutParams.topMargin = layoutParams.topMargin + (int) (dy * density);
setLayoutParams(layoutParams);
requestLayout();
downX = moveX;
downY = moveY;
break;
case MotionEvent.ACTION_UP:
break;
}
return isMove;
}
}