Android 实现简单的悬浮窗按钮(一)

先来看一下实现效果吧

功能较为简单,直接贴出主要实现代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener,View.OnTouchListener{
    private WindowManager.LayoutParams mParams;
    private WindowManager mWindowManager;
    private Button mFloatingButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init(){
        mWindowManager=(WindowManager) getSystemService(Context.WINDOW_SERVICE);
        findViewById(R.id.add).setOnClickListener(this);
        findViewById(R.id.remove).setOnClickListener(this);
    }

    private void requestWindowPermission(){
        //android 6.0或者之后的版本需要发一个intent让用户授权
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if(!Settings.canDrawOverlays(getApplicationContext())){
                Intent intent=new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:"+getPackageName()));
                startActivityForResult(intent,100);
            }
        }
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.add){
            //设置允许弹出悬浮窗口的权限
            requestWindowPermission();
            //创建窗口布局参数
            mParams=new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,0,0,PixelFormat.TRANSPARENT);
            //设置悬浮窗坐标
            mParams.x=100;
            mParams.y=100;
            //表示该Window无需获取焦点,也不需要接收输入事件
            mParams.flags=WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            mParams.gravity = Gravity.LEFT | Gravity.TOP;
            Log.d("MainActivity","sdk:"+Build.VERSION.SDK_INT);
            //设置window 类型
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){//API Level 26
                mParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            } else {
                mParams.type=WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
            }
            //创建悬浮窗(其实就创建了一个Button,这里也可以创建其他类型的控件)
            if(null == mFloatingButton){
                mFloatingButton=new Button(this);
                mFloatingButton.setText("Floating");
                mFloatingButton.setOnTouchListener(this);
                mFloatingButton.setOnClickListener(this);
                mWindowManager.addView(mFloatingButton,mParams);
            }
        } else if(v.getId()==R.id.remove){
            if(null != mFloatingButton){
                mWindowManager.removeView(mFloatingButton);
                mFloatingButton=null;
            }
        } else if(v==mFloatingButton){
            Toast.makeText(getApplicationContext(),"Click",Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int rawX=(int)event.getRawX();
        int rawY=(int)event.getRawY();
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                mParams.x=rawX;
                mParams.y=rawY;
                mWindowManager.updateViewLayout(mFloatingButton,mParams);
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(null != mFloatingButton){
            mWindowManager.removeView(mFloatingButton);
        }
    }
}

相关说明:(源码也已上传,有兴趣的可以获取源码运行一下)

1. 不要忘记在 manifest 文件中添加以下权限

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

因为在android 6.0 以后添加悬浮窗需要在manifest中添加权限:

Checks if the specified context can draw on top of other apps. As of API level 23, an app cannot draw on top of other apps unless it declares the Manifest.permission.SYSTEM_ALERT_WINDOW permission in its manifest, and the user specifically grants the app this capability. To prompt the user to grant this approval, the app must send an intent with the action ACTION_MANAGE_OVERLAY_PERMISSION, which causes the system to display a permission management screen.

详情可以参考 google 文档:

https://developer.android.google.cn/reference/android/provider/Settings?hl=en#canDrawOverlays(android.content.Context)

2. 关于 WindowManager.LayoutParams 中 type参数的设置

由于在 Android 8.0 或者之后的版本 以下字段被废弃

TYPE_SYSTEM_OVERLAY

TYPE_SYSTEM_ERROR

TYPE_PHONE

所以在设置 type 字段时需要进行版本的判断

详细信息也可以参考 Google 官方文档

public static final int TYPE_PHONE

This constant was deprecated in API level 26.
for non-system apps. Use TYPE_APPLICATION_OVERLAY instead.

Google 文档地址:

https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams?hl=en#TYPE_PHONE

资源下载地址:

https://download.csdn.net/download/lollo01/12099115

猜你喜欢

转载自blog.csdn.net/lollo01/article/details/103947163