最近项目里面有使用悬浮签名功能,在github上找了几个项目学了一下,自己并记录一下。
因为目前 我只需要 悬浮 和 手写 两个功能所以我就简单的实现了一下自己的代码:Github
这篇文章只记录悬浮的实现
悬浮权限:
需要添加权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
权限检查:
private void checkSetting() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT).show();
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
} else {
show();
}
} else {
show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
} else {
show();
}
}
}
}
悬浮的实现:
需要获取WindowManager,然后创建自己显示的View,并为View设置LayoutParams,这个过程同其他的ViewGroup是一致的(都实现了ViewManager)
最后 使用 addView(View view, ViewGroup.LayoutParams params) 添加到窗口上
这个类是对悬浮窗的定义,包含view 和 布局参数 的生成:
/**
* @program: DoodleView
* @description: Describe the floating view and control how it is displayed
* @author: lee
* @create: 2020-12-21 15:00
*/
public interface ISuspension {
WindowManager.LayoutParams getLayoutParams();
View createView();
}
WindowManager windowManager;
View showingView;
private void create() {
// 新建悬浮窗控件
showingView = suspension.createView();
WindowManager.LayoutParams layoutParams = suspension.getLayoutParams();
// 将悬浮窗控件添加到WindowManager
getWindowManager().addView(showingView, layoutParams);
}
这里的view就是普通的View即可
ViewGroup.LayoutParams 需要注意的就比较多了,也是悬浮实现的重要类:
1.属性的设置
@Override
public WindowManager.LayoutParams getLayoutParams() {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//layoutParams.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
//app 内有效
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
}
//整个 系统有效(慎用)
//layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
//设置没有焦点不能touch,这样其他的界面才可以滑动和操作
//如果想独占触摸事件就关闭这句话
// layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
layoutParams.format = PixelFormat.RGBA_8888;
//获取屏幕大小
Display display = getWindowManager().getDefaultDisplay();
Point outSize = new Point();
display.getSize(outSize);
int width = outSize.x;
int height = outSize.y;
//根据需要设置位置大小
layoutParams.width = width;
layoutParams.height = height / 2;
layoutParams.x = 0;
layoutParams.y = height / 2;
return layoutParams;
}
2.大小位置的设置
//获取屏幕大小
Display display = getWindowManager().getDefaultDisplay();
Point outSize = new Point();
display.getSize(outSize);
int width = outSize.x;
int height = outSize.y;
//根据需要设置位置大小
layoutParams.width = width;
layoutParams.height = height / 2;
layoutParams.x = 0;
layoutParams.y = height / 2;
现在简单的悬浮就可以实现了,至于 状态改变(平移,变大小,变透明,动画效果),我后面有用到我再来记录!!!
加餐
从这个结构我们可以看出来所有属性中的重点中的重点就是这这定义了>。<
他们分别对应属性:type(窗口类型),flags(各种行为选项/标志),softInputMode(任何软输入区域所需的操作模式),layoutInDisplayCutoutMode(如果存在,控制窗口的布局方式DisplayCutout
)。
type - 在API级别1中添加
窗口的常规类型。窗口类型主要分为三类:
- 应用程序窗口(范围从
FIRST_APPLICATION_WINDOW
到LAST_APPLICATION_WINDOW
)是普通的顶级应用程序窗口。对于这些类型的窗口,token
必须将设置为它们所属的活动的令牌(如果token
为null,通常会为您完成)。 - 子窗口(从
FIRST_SUB_WINDOW
到LAST_SUB_WINDOW
)与另一个顶级窗口相关联。对于这些类型的窗口,token
必须是其所连接的窗口的标记。 - 系统窗口(范围从
FIRST_SYSTEM_WINDOW
到LAST_SYSTEM_WINDOW
)是供系统用于特定目的的特殊类型的窗口。应用程序通常不应使用它们,并且需要特殊许可才能使用它们。
常用值:
TYPE_ACCESSIBILITY_OVERLAY:仅被连接覆盖的窗口,用于拦截用户交互,而不会更改可访问性服务可以自检的窗口。特别是,可访问性服务只能自检可见用户可以与之交互的窗口,他们可以触摸这些窗口或可以键入这些窗口。例如,如果有一个可触摸的全屏可访问性覆盖,则可访问性服务将自检其下方的窗口,即使它们被可触摸窗口覆盖。
TYPE_APPLICATION:(Activity内有效)普通应用程序窗口。的token
必须是令牌识别窗口属于谁的活动。在多用户系统中,仅在拥有用户的窗口上显示。
TYPE_APPLICATION_ATTACHED_DIALOG:类似TYPE_APPLICATION_PANEL
,但是窗口的布局与顶级窗口的布局相同,而不是其容器的子级。
TYPE_APPLICATION_MEDIA:用于显示媒体(例如视频)的窗口。这些窗口显示在其附加窗口的后面。
TYPE_APPLICATION_OVERLAY: (APP内有效)应用程序覆盖窗口显示在所有活动窗口上方(介于FIRST_APPLICATION_WINDOW
和之间的类型LAST_APPLICATION_WINDOW
),但显示在关键系统窗口(例如状态栏或IME)下方。系统可以随时更改这些窗口的位置,大小或可见性,以减少用户的视觉混乱并管理资源。需要android.Manifest.permission#SYSTEM_ALERT_WINDOW
许可。系统将使用这种窗口类型调整进程的重要性,以减少低内存杀手杀死进程的机会。在多用户系统中,仅在拥有用户的屏幕上显示。
TYPE_PHONE(慎用):(整个系统有效)窗口类型:电话。这些是非应用程序窗口,提供用户与电话的交互(尤其是来电)。这些窗口通常位于所有应用程序的上方,但位于状态栏的后面。在多用户系统中,在所有用户的窗口上显示。
TYPE_SYSTEM_ALERT(慎用):窗口类型:系统窗口,例如低电量警报。这些窗口始终位于应用程序窗口的顶部。在多用户系统中,仅在拥有用户的窗口上显示。
-------有状态的
TYPE_STATUS_BAR:窗口类型:状态栏。只能有一个状态栏窗口。它位于屏幕顶部,所有其他窗口都向下移,使其位于屏幕下方。在多用户系统中,在所有用户的窗口上显示。
TYPE_INPUT_METHOD:窗口类型:内部输入法窗口,显示在普通UI上方。可以调整应用程序窗口的大小或平移该窗口,以保持输入焦点在显示此窗口时可见。在多用户系统中,仅在拥有用户的窗口上显示。
flags - Added in API level 1
Various behavioral options/flags. Default is none.
See Also
#FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
#FLAG_DIM_BEHIND
#FLAG_NOT_FOCUSABLE
#FLAG_NOT_TOUCHABLE
#FLAG_NOT_TOUCH_MODAL
#FLAG_TOUCHABLE_WHEN_WAKING
#FLAG_KEEP_SCREEN_ON
#FLAG_LAYOUT_IN_SCREEN
#FLAG_LAYOUT_NO_LIMITS
#FLAG_FULLSCREEN
#FLAG_FORCE_NOT_FULLSCREEN
#FLAG_SECURE
#FLAG_SCALED
#FLAG_IGNORE_CHEEK_PRESSES
#FLAG_LAYOUT_INSET_DECOR
#FLAG_ALT_FOCUSABLE_IM
#FLAG_WATCH_OUTSIDE_TOUCH
#FLAG_SHOW_WHEN_LOCKED
#FLAG_SHOW_WALLPAPER
#FLAG_TURN_SCREEN_ON
#FLAG_DISMISS_KEYGUARD
#FLAG_SPLIT_TOUCH
#FLAG_HARDWARE_ACCELERATED
#FLAG_LOCAL_FOCUS_MODE
#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
softInputMode - 在API级别3中添加
任何软输入区域所需的操作模式。可以是以下各项的任意组合:
- 其中的可见性状态的
SOFT_INPUT_STATE_UNSPECIFIED
,SOFT_INPUT_STATE_UNCHANGED
,SOFT_INPUT_STATE_HIDDEN
,SOFT_INPUT_STATE_ALWAYS_HIDDEN
,SOFT_INPUT_STATE_VISIBLE
,或SOFT_INPUT_STATE_ALWAYS_VISIBLE
。 - 其中一个调节选项
SOFT_INPUT_ADJUST_UNSPECIFIED
,SOFT_INPUT_ADJUST_RESIZE
,SOFT_INPUT_ADJUST_PAN
,或SOFT_INPUT_ADJUST_NOTHING
。
可以通过android.R.attr#windowSoftInputMode
属性在主题中控制此标志。
layoutInDisplayCutoutMode - 在API级别28中添加
如果存在,控制窗口的布局方式DisplayCutout
。
默认为LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
。
值可以是0
或的组合android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
,android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
,android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
,和android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS