实现悬浮球需要了解
- Winodw和WindowManager
- Serivce
版本:Android10 Android studio版本:2020.3.1 targetVersion :30 (需26+) 开发时gradle版本;com.android.tools.build:gradle:7.0.0 应用权限:ACTION_MANAGE_OVERLAY_PERMISSION
实现的效果:
- 可短按
- 可长按(在刚点击的时候,不会触发短按点击事件),可两次长按
- 10秒钟不点击,变成透明度80%的悬浮球,不会遮挡到悬浮球后方文字
悬浮球预览:(想要无损图片的关注私聊我)
开始实现
1.使用类型
首先要明确,Activity是无法完成在桌面悬浮的一个悬浮球的,我们必须要用到Service,这里不赘述,Service和Activity很类似,但是前置主要用于一些后台服务,配合WindowManager可以完成悬浮球的效果(应用程序关闭,服务关闭)。
2.权限
至少需要用到弹窗权限,如果悬浮球需要添加其他功能,按需添加权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
3.准备图片资源
需要的关注私聊
4.编写代码
1.获取屏幕参数
public void getSizeOfScreen(){
WindowManager windowManager=(WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
SCREEN_HEIGHT=windowManager.getDefaultDisplay().getHeight();
SCREEN_WIDTH=windowManager.getDefaultDisplay().getWidth();
}
屏幕参数在这里很重要,防止悬浮球遇到显示在屏幕外
2.initWindowManager
@RequiresApi(api = Build.VERSION_CODES.O)
@SuppressLint("ClickableViewAccessibility")
public void initWindowManager() {
windowManager = (WindowManager) getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
params.format = PixelFormat.RGBA_8888;
setSizeOfBall();
params.gravity = Gravity.LEFT;
params.x = 200;
params.y = 000;
}
代码中的if-else语句很重要,在网上某些过时的博客中,没有这段代码,会报权限类型错误 注:parm代表的就是悬浮球的所在位置 想控制自己的悬浮球一定要知道安卓手机屏幕的View坐标系 3.代码
public void Drag() {
if (IS_SHOW) {
floatView.setOnTouchListener(new View.OnTouchListener() {
int lastX, lastY;
int paramX, paramY;
int old_dx = 0, old_dy = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
paramX = params.x;
paramY = params.y;
isMove=true;
setDrawable();
downTime=System.currentTimeMillis();
Log.i(TAG, "onTouch: ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
params.x = paramX + dx;
params.y = paramY + dy;
isLongPress(event,lastX,lastY);
windowManager.updateViewLayout(floatView, params);
Log.i(TAG, "onTouch:ACTION_MOVE");
old_dy = dy;
old_dx = dx;
IsTransparent=false;
handler.removeMessages(flag3);
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouch: ACTION_CANCEL" );
if (params.x>SCREEN_WIDTH/2){
params.x=SCREEN_WIDTH;
windowManager.updateViewLayout(floatView,params);
}
else{
params.x=0;
windowManager.updateViewLayout(floatView,params);
}
isOnceLongPress=false;
isMove=false;
isTwiceLongPress=false;
Transparent();
break;
}
v.performClick();
return true;
}
});
windowManager.addView(floatView, params);
Log.i(TAG, "Drag: 悬浮球已经addView");
}
}
给悬浮球加了监听器,监听其的点击,并实现跟随点击改变位置 图中用到了Handler,是为了解决一个自定义手势,两次长按事件 这里不详细解释Handler是什么,简而言之说明其功能,就是在代码中可以发送信号,然后Handler 接收到信号后执行相应代码,并且有延迟发送,和取消发送功能。
我在demo中用到了以下功能
- 延迟发送:可以解决悬浮球在非点击后10秒钟就改变透明度的事件
- 取消发送:假如10秒内有点击事件,取消发送改变透明度的信号
注意:延迟发送信号一定会到达的,并且一定会触发相应代码,触发在发送之前取消发送 handler.sendEmptyMessageDelayed(flag1,1000);
@SuppressLint("HandlerLeak")
public void initHandler(){
handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case flag1:
isOnceLongPress=true;
handler.removeMessages(flag1);
Log.d(TAG, "handleMessage: 长按事件1" );
break;
case flag2:
isTwiceLongPress=true;
handler.removeMessages(flag2);
Log.d(TAG, "handleMessage: 长按事件2" );
break;
case flag3:
IsTransparent=true;
handler.removeMessages(flag3);
Log.d(TAG, "handleMessage: 透明事件" );
floatView.setBackgroundResource(R.drawable.ic_floatball_transparent80);
break;
}
}
};
}
给悬浮球设置图片:如果透明就设置图片,如果没有显示就创建
public void setDrawable() {
if (IsTransparent){
floatView.setBackgroundResource(R.drawable.ic_float_ball);
return;
}
if (!IS_SHOW) {
floatView = new View(getApplicationContext());
floatView.setBackgroundResource(R.drawable.ic_float_ball);
IS_SHOW = true;
Log.d(TAG, "setDrawable: 悬浮球图片已加载完成");
}
}
需要demo私聊
|