自定义控件类
public class FloatingCilcleView extends View {
// 控件上的文字
private String text = "点击隐藏";
// 控件的半径
private int radius = dp2px(60);
// 控件的宽
private int width = radius * 2;
// 控件的高
private int height = radius * 2;
private Paint textPaint;
private Paint cilclePaint;
public FloatingCilcleView(Context context) {
this(context, null);
}
public FloatingCilcleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public FloatingCilcleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyleAttrs(context, attrs);
}
private void obtainStyleAttrs(Context context, AttributeSet attrs) {
textPaint = new Paint();
textPaint.setColor(0xAAFF0000);
textPaint.setTextSize(sp2px(20));
textPaint.setAntiAlias(true);
textPaint.setDither(true);
textPaint.setFakeBoldText(true);
textPaint.setStyle(Paint.Style.FILL);
cilclePaint = new Paint();
cilclePaint.setColor(0x55D2D2D2);
cilclePaint.setDither(true);
cilclePaint.setAntiAlias(true);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width, height);
}
@Override
protected synchronized void onDraw(Canvas canvas) {
// 画圆
canvas.drawCircle(width / 2, height / 2, radius, cilclePaint);
int x = (int) (width / 2 - textPaint.measureText(text) / 2);
// 基线
Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
int baseLine = getHeight() / 2 + dy;
// 绘制文字
canvas.drawText(text, x, baseLine, textPaint);
}
private int dp2px(int value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
getResources().getDisplayMetrics());
}
private int sp2px(int value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, value,
getResources().getDisplayMetrics());
}
}
WindowManager管理器
public class FloatingViewManager {
// 悬浮控件移动的X值
private float startX = 0f;
// 悬浮控件移动的Y值
private float startY = 0f;
// 用于记录解决OnTouch与OnClick事件冲突的X值
private float startX1 = 0f;
// 用于记录解决OnTouch与OnClick事件冲突的Y值
private float startY1 = 0f;
// 悬浮控件
private FloatingCilcleView cilcleView;
private Context context;
private WindowManager wm;
private WindowManager.LayoutParams params;
private static FloatingViewManager instance;
public static FloatingViewManager getInstance(Context context) {
if (instance == null) {
synchronized (FloatingViewManager.class) {
if (instance == null) {
instance = new FloatingViewManager(context);
}
}
}
return instance;
}
private View.OnTouchListener touchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = startX1 = event.getRawX();
startY = startY1 = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float x = event.getRawX();
float y = event.getRawY();
float dx = x - startX;
float dy = y - startY;
params.x += dx;
params.y += dy;
wm.updateViewLayout(cilcleView, params);
startX = x;
startY = y;
break;
case MotionEvent.ACTION_UP:
float endX = event.getRawX();
float endY = event.getRawY();
int width = getWindowWidth();
if (endX > (float) (width / 2)) { // 记录悬浮控件最后停在屏幕的左右哪一边
params.x = width - cilcleView.getWidth();
} else {
params.x = 0;
}
params.y = (int) endY;
wm.updateViewLayout(cilcleView, params);
// 解决OnTouch与OnClick事件冲突
if ((Math.abs((endX - startX1)) > 4) || (Math.abs((endY - startY1)) > 4)) {
return true;
} else {
return false;
}
default:
break;
}
return false;
}
};
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
wm.removeView(cilcleView); // 移除悬浮控件
}
};
private FloatingViewManager(Context context) {
this.context = context;
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
cilcleView = new FloatingCilcleView(context);
cilcleView.setOnTouchListener(touchListener);
cilcleView.setOnClickListener(clickListener);
}
public void showFloatingCilcleView() {
params = new WindowManager.LayoutParams();
params.width = cilcleView.getWidth();
params.height = cilcleView.getHeight();
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = 0; // x、y是相对于params.gravity的偏移量
params.y = 0;
params.format = PixelFormat.RGBA_8888;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
}
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
wm.addView(cilcleView, params);
}
// 获取屏幕的宽度
private int getWindowWidth() {
return wm.getDefaultDisplay().getWidth();
}
}
使用Service来显示悬浮控件
public class FloatingService extends Service {
@Override
public void onCreate() {
FloatingViewManager manager = FloatingViewManager.getInstance(this);
manager.showFloatingCilcleView();
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
在Activity中开启Service
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
}
// 按钮点击事件
public void open(View view) {
Intent intent = new Intent(this, FloatingService.class);
startService(intent);
finish();
}
private void requestPermission() {
// 判断权限是否授权
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.SYSTEM_ALERT_WINDOW }, 200);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 200:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("xxx", "已授权权限申请");
} else {
Log.i("xxx", "未授权权限申请");
}
break;
}
}
}