Float Window
1.权限与开启服务
权限
<!--2.悬浮窗警报开启-->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
注册服务
<service android:name=".FloatingWindow"/><!--2.这里是注册服务-->
开启服务(这里是开启服务可以后台,而绑定服务可以传值)
startService(new Intent(this, FloatingWindow.class));//1.开启服务
2.服务类
继承与重写,服务作用:可以在后台运行
extends Service
//重写onBind,必须的
onBind
//onCreate,自己创建
onCreate
创建,LinearLayout,Button,WindowManager
LinearLayout用LinearLayout.LayoutParams设置参数
Button用ViewGroup.LayoutParams设置参数
WindowManager用WindowManager.LayoutParams设置参数
button加LinearLayout里,LineaLayout加到WindowManager里。
3.设置移动监听
touch监听:触碰是为了得到此位置
移动则可以得到移动后的位置,
两者结合便可以得到我们想要的距离
再在WindowManager更新得到我们想要的距离
4.stop
WindowManager移除LinearLayout,再停止服务
5.代码
package com.example.examplefloatwindows;
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
public class FloatingWindow extends Service {
private WindowManager wm;
private LinearLayout ll;
private String TAG = FloatingWindow.class.getName();
private Button stop;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
wm = (WindowManager) getSystemService(WINDOW_SERVICE);//3.得到系统服务
ll = new LinearLayout(this);//在this这里创建LinearLayout
LinearLayout.LayoutParams LLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);//得到LL的layoutParams实例,设置布局高宽
ll.setBackgroundColor(Color.argb(66, 255, 0, 0));//透明度,红色,绿色,蓝色
ll.setLayoutParams(LLayoutParams);//设置布局参数
final WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(400, 150, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);//WindowManager参数实例化
parameters.x = 0;parameters.y = 0;//位置
parameters.gravity = Gravity.CENTER | Gravity.CENTER;//重心居中
/**
* 按钮
*/
stop=new Button(this);
ViewGroup.LayoutParams btnParamters=new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
stop.setText("stop");
stop.setLayoutParams(btnParamters);
ll.addView(stop);
wm.addView(ll, parameters);//加入View,参数
ll.setOnTouchListener(new View.OnTouchListener() {
private WindowManager.LayoutParams updatedParameters = parameters;
int x, y;
float touchedX, touchedY;
@Override
public boolean onTouch(View v, MotionEvent event) {//布局,点击之后的位置,级短时间内就更新
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = updatedParameters.x;y = updatedParameters.y;//更新的x,y(其实他就是WindowManager的位置),此时都为0
touchedX = event.getRawX();touchedY = event.getRawY();//这里表示得到原来的x,y
Log.d(TAG, "\n" + x + "\n" + y + "\n" + touchedX + "\n" + touchedY);
break;
case MotionEvent.ACTION_MOVE:
updatedParameters.x = (int) (x + (event.getRawX() - touchedX));updatedParameters.y = (int) (y + (event.getRawY() - touchedY));//getRawY表示移动后现在的距离左侧位置长度,
wm.updateViewLayout(ll, updatedParameters);//更新位置
Log.d(TAG, "\n" + x + "\n" + y + "\n" + touchedX + "\n" + touchedY);
}
return false;
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
wm.removeView(ll);//移除布局
stopSelf();//移除service
}
});
}
}
蹦掉怎么办
修改后代码
MainActivity.class
package com.example.examplefloatwindows;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mBtFloatWindows;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mBtFloatWindows = (Button) findViewById(R.id.bt_floatWindows);
mBtFloatWindows.setOnClickListener(this);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_floatWindows:
//如果是已经悬浮状态,就跳出去,都不执行
if (FloatingWindow.isStarted) {
return;
}
//如果不可以叠加型绘制
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);//显示无权限信息
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);//跳转到手机权限设置那里
} else {//可以叠加绘制
startService(new Intent(MainActivity.this, FloatingWindow.class));
}
startService(new Intent(this, FloatingWindow.class));//1.开启服务
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("onActivityResult", "我是这个时候开始的");
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
startService(new Intent(MainActivity.this, FloatingWindow.class));
}
} else {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
startService(new Intent(MainActivity.this, FloatingWindow.class));
}
}
}
}
FloatingWindow.java
package com.example.examplefloatwindows;
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
public class FloatingWindow extends Service {
private WindowManager wm;
private LinearLayout ll;
private String TAG = FloatingWindow.class.getName();
public static boolean isStarted = false;//默认为不显示
private Button stop;
private int typeApplicationOverlay;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
isStarted=true;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);//3.得到系统服务
ll = new LinearLayout(this);//在this这里创建LinearLayout
LinearLayout.LayoutParams LLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);//得到LL的layoutParams实例,设置布局高宽
ll.setBackgroundColor(Color.argb(66, 255, 0, 0));//透明度,红色,绿色,蓝色
ll.setLayoutParams(LLayoutParams);//设置布局参数
// 设置窗体显示类型
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
typeApplicationOverlay = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
typeApplicationOverlay = WindowManager.LayoutParams.TYPE_PHONE;
}
final WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(400, 150, typeApplicationOverlay, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);//WindowManager参数实例化
parameters.x = 0;parameters.y = 0;//位置
parameters.gravity = Gravity.CENTER | Gravity.CENTER;//重心居中
/**
* 按钮
*/
stop=new Button(this);
ViewGroup.LayoutParams btnParamters=new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
stop.setText("stop");
stop.setLayoutParams(btnParamters);
ll.addView(stop);
wm.addView(ll, parameters);//加入View,参数
ll.setOnTouchListener(new View.OnTouchListener() {
private WindowManager.LayoutParams updatedParameters = parameters;
int x, y;
float touchedX, touchedY;
@Override
public boolean onTouch(View v, MotionEvent event) {//布局,点击之后的位置,级短时间内就更新
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = updatedParameters.x;y = updatedParameters.y;//更新的x,y(其实他就是WindowManager的位置),此时都为0
touchedX = event.getRawX();touchedY = event.getRawY();//这里表示得到原来的x,y
Log.d(TAG, "\n" + x + "\n" + y + "\n" + touchedX + "\n" + touchedY);
break;
case MotionEvent.ACTION_MOVE:
updatedParameters.x = (int) (x + (event.getRawX() - touchedX));updatedParameters.y = (int) (y + (event.getRawY() - touchedY));//getRawY表示移动后现在的距离左侧位置长度,
wm.updateViewLayout(ll, updatedParameters);//更新位置
Log.d(TAG, "\n" + x + "\n" + y + "\n" + touchedX + "\n" + touchedY);
}
return false;
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isStarted=false;
wm.removeView(ll);//移除布局
stopSelf();//移除service
}
});
}
}
添加了什么:
TYPE要修改,因为有些只能支持TYPE_APPLICATION_OVERLAY,不支持TYPE_PHONE
// 设置窗体显示类型
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
typeApplicationOverlay = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
typeApplicationOverlay = WindowManager.LayoutParams.TYPE_PHONE;
}