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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章