Android 实现悬浮窗

一、创建悬浮窗服务

public class FloatingService extends Service {
    private static final String TAG = "xuwei";
    public static boolean isStarted = false;

    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;
    private View displayView;

    @Override
    public void onCreate() {
        super.onCreate();
    
        isStarted = true;
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        layoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        layoutParams.format = PixelFormat.RGBA_8888;
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.width = 200;
        layoutParams.height = 200;
        layoutParams.x = 540;
        layoutParams.y = 960;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public class MyBinder extends Binder {
        public FloatingService getService() {
            return FloatingService.this;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: 服务运行");
        showFloatingWindow();
        return super.onStartCommand(intent, flags, startId);
    }

    public void showFloatingWindow() {
        if (Settings.canDrawOverlays(this)) {
            LayoutInflater layoutInflater = LayoutInflater.from(this);
            displayView = layoutInflater.inflate(R.layout.layout_display, null);//悬浮窗口显示的view
            windowManager.addView(displayView, layoutParams);

            displayView.setOnTouchListener(new FloatingOnTouchListener());
            //悬浮框点击事件
            displayView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //在这里实现点击重新回到Activity
                    Intent intent = new Intent(FloatingService.this, FloatActivity.class);
                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
                    intent.setAction(Intent.ACTION_MAIN);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                    startActivity(intent);
                }
            });
        }
    }

    public void closeFloatingWindow() {
        if (displayView != null) {
            // 移除悬浮窗口
            windowManager.removeView(displayView);
        }
    }

    //判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件
    private boolean isMove;
    private int mStartX, mStartY, mStopX, mStopY;

    private class FloatingOnTouchListener implements View.OnTouchListener {
        private int x;
        private int y;

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
//                    clicks(500);//双击悬浮窗重新进入activiy
                    mStartX = (int) event.getX();
                    mStartY = (int) event.getY();
                    isMove = false;
                    x = (int) event.getRawX();
                    y = (int) event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int nowX = (int) event.getRawX();
                    int nowY = (int) event.getRawY();
                    int movedX = nowX - x;
                    int movedY = nowY - y;
                    x = nowX;
                    y = nowY;
                    layoutParams.x = layoutParams.x + movedX;
                    layoutParams.y = layoutParams.y + movedY;
                    windowManager.updateViewLayout(view, layoutParams);
                    break;
                case MotionEvent.ACTION_UP:
                    mStopX = (int) event.getX();
                    mStopY = (int) event.getY();
                    if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) {
                        isMove = true;
                    }
                    break;
                default:
                    break;
            }
            //如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件
            return isMove;
//            return false;
        }
    }

    private long firstClickTime = 0;

    private void clicks(int intervalTime) { //双击重新回到activity, intervalTime:最长间隔时间
        if (firstClickTime > 0) {
            if (System.currentTimeMillis() - firstClickTime < intervalTime) {
                firstClickTime = 0; // 将第一次点击时间置为0

                //唤起activity
                Intent intent = new Intent(this, FloatActivity.class);
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                intent.setAction(Intent.ACTION_MAIN);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                startActivity(intent);
            }
        }
        firstClickTime = System.currentTimeMillis();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (displayView != null) {
            // 移除悬浮窗口
            windowManager.removeView(displayView);
        }
    }
}

二、需要实现悬浮窗的activity

1.FloatActivity的启动模式设置为

android:launchMode="singleInstance"

2.AndroidManifest设置权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

3.FloatActivity

 

public class FloatActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_float);
        checkPermission();
    }
//动态权限申请,其它权限当需要
    private void checkPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)
                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
            settingPermission();
        } else if (ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            //没有权限,向用户请求权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
                    CODE_FOR_WRITE_PERMISSION);
        }
    }

    private void settingPermission() {
        new AlertDialog.Builder(this)
                .setMessage("请到'设置'-‘权限管理'设置相关权限’")
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", getPackageName(), null);
                        intent.setData(uri);
                        startActivityForResult(intent, REQUEST_RECORD_PERMISSION_SETTING);
                    }
                })
                .create()
                .show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_RECORD_PERMISSION_SETTING) {
            checkPermission();
        }
        if (requestCode == 2) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
                //startService(new Intent(FloatActivity.this, FloatingService.class));
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //通过requestCode来识别是否同一个请求
        if (requestCode == CODE_FOR_WRITE_PERMISSION) {
            boolean hasPermisson = true;
            for (int status : grantResults) {
                if (status != PackageManager.PERMISSION_GRANTED) {
                    hasPermisson = false;
                    break;
                }
            }
            if (!hasPermisson) {
                //用户不同意,向用户展示该权限作用
                settingPermission();
            }
        }
    }
 
@Override
protected void onRestart() {//重新回到activity
    super.onRestart();
    unbindService(mVideoServiceConnection);//不显示悬浮框
    iskServStart = false;
}

    private boolean iskServStart = false;
    FloatingService service1;
    ServiceConnection mVideoServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 获取服务的操作对象
            FloatingService.MyBinder binder = (FloatingService.MyBinder) service;
            service1 = binder.getService();
            service1.showFloatingWindow();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (service1 != null) {
                service1.closeFloatingWindow();//关闭悬浮窗
                service1 = null;
            }
        }
    };

//按钮的点击事件,开启/关闭悬浮窗
    public void ben_float(View view) {
        if (!Settings.canDrawOverlays(this)) {//需要minSdkVersion23以上
            Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
            startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);
        } else {
            if (!iskServStart) {
                iskServStart = !iskServStart;
                Toast.makeText(FloatActivity.this, "开启悬浮窗", Toast.LENGTH_SHORT).show();
                moveTaskToBack(true);//最小化Activity
                Intent intent = new Intent(this, FloatingService.class);//开启服务显示悬浮框
                bindService(intent, mVideoServiceConnection, Context.BIND_AUTO_CREATE);
            } else {
                iskServStart = !iskServStart;
                Toast.makeText(FloatActivity.this, "关闭悬浮窗", Toast.LENGTH_SHORT).show();
                unbindService(mVideoServiceConnection);
            }
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值