天天看點

15 懸浮視窗一 需求二 API三 注意事項四 代碼實作五 Demo

DailyWorkSummary

文章目錄

  • 一 需求
  • 二 API
  • 三 注意事項
    • 1 權限擷取
    • 2 LayoutParams
    • 3 不能重複定義LayoutParams
  • 四 代碼實作
    • 1 MyApplication
    • 2 FloatView
    • 3 FloatingWindowActivity
  • 五 Demo

一 需求

實作類似微信聊天的懸浮框效果,加載在Activity頁面之上,可以用來做一個唯一的強制操作

二 API

  • WindowManager的addView和removeView實作

三 注意事項

1 權限擷取

動态權限判斷

if (!Settings.canDrawOverlays(this)) {
                startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
            }else{
                showView();
            }
           

2 LayoutParams

3 不能重複定義LayoutParams

四 代碼實作

1 MyApplication

public class MyApplication extends Application {

    /**
     * 建立全局變量
     * 全局變量一般都比較傾向于建立一個單獨的資料類檔案,并使用static靜态變量
     *
     * 這裡使用了在Application中添加資料的方法實作全局變量
     * 注意在AndroidManifest.xml中的Application節點添加android:name=".MyApplication"屬性
     *
     */
    private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();


    public WindowManager.LayoutParams getMywmParams(){
        return wmParams;
    }

}
           

2 FloatView

public class FloatView extends View {
    private float mTouchStartX;
    private float mTouchStartY;
    private float x;
    private float y;

    private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    private WindowManager.LayoutParams wmParams = ((MyApplication)getContext().getApplicationContext()).getMywmParams();



    public FloatView(Context context) {
        super(context);
    }



    @Override
    public boolean onTouchEvent(MotionEvent event) {

        //擷取相對螢幕的坐标,即以螢幕左上角為原點
        x = event.getRawX();
        y = event.getRawY()-25;   //25是系統狀态欄的高度
        Log.i("currP", "currX"+x+"====currY"+y);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //擷取相對View的坐标,即以此View左上角為原點
                mTouchStartX =  event.getX();
                mTouchStartY =  event.getY();

                Log.i("startP", "startX"+mTouchStartX+"====startY"+mTouchStartY);

                break;
            case MotionEvent.ACTION_MOVE:
                updateViewPosition();
                break;

            case MotionEvent.ACTION_UP:
                updateViewPosition();
                mTouchStartX=mTouchStartY=0;
                break;
        }
        return true;
    }

    private void updateViewPosition(){
        //更新浮動視窗位置參數
        wmParams.x=(int)( x-mTouchStartX);
        wmParams.y=(int) (y-mTouchStartY);
        wm.updateViewLayout(this, wmParams);
    }

}
           

3 FloatingWindowActivity

public class FloatingWindowActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 101;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.floating_window_activity);


    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(REQUEST_CODE == requestCode){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(this)) {
                    Toast.makeText(this, "授權失敗", Toast.LENGTH_SHORT).show();
                } else{
                    showView();
                }
            }
        }
    }

    public void start(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
            }else{
                showView();
            }
        }else{
            showView();
        }
    }

    private void addView(){
        // 擷取WindowManager服務
        final WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        // 建立懸浮窗

        // 控件
        final Button button = new Button(getApplicationContext());
        button.setText("Floating Window");
        button.setBackgroundColor(Color.BLUE);

        // 設定LayoutParam
        WindowManager.LayoutParams 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.width = 500;
        layoutParams.height = 100;
        layoutParams.x = 300;
        layoutParams.y = 300;

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                windowManager.removeView(button);
                //   startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
        // 将懸浮窗控件添加到WindowManager
        windowManager.addView(button, layoutParams);
    }

    private WindowManager mWindowManager;
    private WindowManager.LayoutParams param;
    private List<FloatView> list = new ArrayList<>();

    private void showView(){
        FloatView mLayout=new FloatView(getApplicationContext());
        mLayout.setBackgroundColor(Color.RED);
        //擷取WindowManager
        mWindowManager=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        //設定LayoutParams(全局變量)相關參數
        param = ((MyApplication)getApplication()).getMywmParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            param.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            param.type = WindowManager.LayoutParams.TYPE_PHONE;
        }

        param.format=1;
        param.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 不能搶占聚焦點
        param.flags = param.flags | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
        param.flags = param.flags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; // 排版不受限制

        param.alpha = 1.0f;

        param.gravity= Gravity.LEFT|Gravity.TOP;   //調整懸浮視窗至左上角
        //以螢幕左上角為原點,設定x、y初始值
        param.x=0;
        param.y=0;

        //設定懸浮視窗長寬資料
        param.width=140;
        param.height=140;

        //顯示myFloatView圖像
        mWindowManager.addView(mLayout, param);
        list.add(mLayout);
    }

    @Override
    protected void onDestroy() {
        for(View v:list){
            mWindowManager.removeView(v);
        }
        super.onDestroy();
    }
}

           

五 Demo

FloatingWindowActivity

繼續閱讀