Android 添加全局彈窗

image.png

對(duì)于一些提示我們并不依賴與任何界面酒觅,如上圖撮执。

有很多方式可以實(shí)現(xiàn),\color{#FF3030}{第一種}方式是自定義Toast舷丹。但是這種方式在華為手機(jī)(還有一些其他手機(jī))上不能點(diǎn)擊Toast時(shí)間,需要我們自己setOnTouchListener來處理蜓肆。并且這樣使得整個(gè)App都會(huì)相應(yīng)Touch事件颜凯。需要自己處理。

具體處理思路:自定義Toast仗扬,設(shè)置setOnTouchListener症概,然后判斷是否在點(diǎn)擊的區(qū)域,再做觸摸防抖處理早芭。雖然麻煩點(diǎn)彼城,也算是完美解決。貼上代碼

        Toast mCustomToast = new Toast(HiFrameworkApplication.getInstance());
        mCustomToast.setDuration(Toast.LENGTH_SHORT);
        mCustomToast.setGravity(Gravity.BOTTOM, 0, 0);
        final LayoutInflater inflater = LayoutInflater.from(HiFrameworkApplication.getInstance());
        final View layoutView = inflater.inflate(R.layout.fp_fpbphone_custom_alarm_toast, null);
        RelativeLayout root = layoutView.findViewById(R.id.fp_fpbphone_root);
        TextView mTvTime = layoutView.findViewById(R.id.tv_fp_fpbphone_custom_alarm_toast_time);
        TextView mTvContent = layoutView.findViewById(R.id.tv_fp_fpbphone_custom_alarm_toast_content);
        TextView click = layoutView.findViewById(R.id.tv_fp_fpbphone_custom_alarm_toast_detail);
        mTvTime.setText(time);
        mTvContent.setText(content);
        //有id才可點(diǎn)擊
        click.setFocusable(true);
        click.setVisibility(TextUtils.isEmpty(alarmId) ? View.GONE : View.VISIBLE);
        layoutView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //判斷當(dāng)前點(diǎn)擊位置
                final int rawY = (int) event.getRawY();
                final int rawX = (int) event.getRawX();
                //點(diǎn)擊的位置必須大于屏幕高度-控件的高度
                Log.d("azy", "width" + layoutView.getWidth() + "  height" + layoutView.getHeight());

//               判斷是不是在區(qū)域范圍內(nèi)
                if (isInView(layoutView,rawX,rawY)){
                    LogUtil.d("azy", "mScreenHight " + mScreenHight + "  rawY  " + rawY);
                    if (DuplicateClicksUtil.isFastClick()) {
                        LogUtil.d("azy", "onTouch");
                        EventBus.getDefault().post(new AlarmClickEvent(alarmId));

                        Intent intent =
                                new Intent(HiFrameworkApplication.getInstance(), AlarmDetailActivity.class);
                        Bundle bundle = new Bundle();
                        bundle.putString(Cons.INTENT_ALARM_ID, alarmId);
                        intent.putExtras(bundle);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        HiFrameworkApplication.getInstance().startActivity(intent);
                    }
                }
                return true;
            }
        });

        try {
            Object mTN;
            mTN = getField(mCustomToast, "mTN");
            if (mTN != null) {
                Object mParams = getField(mTN, "mParams");
                if (mParams != null
                        && mParams instanceof WindowManager.LayoutParams) {
                    final WindowManager.LayoutParams params = (WindowManager.LayoutParams) mParams;
                    //顯示與隱藏動(dòng)畫
//                            params.windowAnimations = R.style.ClickToast;
                    //Toast可點(diǎn)擊退个,這里的屬性設(shè)置很重要
                    params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

                    //設(shè)置viewgroup寬高
                    params.width = WindowManager.LayoutParams.MATCH_PARENT; //設(shè)置Toast寬度為屏幕寬度
                    params.height = WindowManager.LayoutParams.WRAP_CONTENT; //設(shè)置高度


                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        mCustomToast.setView(layoutView);
        mCustomToast.show();

關(guān)于判斷對(duì)應(yīng)控件區(qū)域的代碼如下:

    private Rect mViewRect;
    private boolean isInView(View view,int x, int y){
        if (mViewRect == null){
            mViewRect = new Rect();
        }
        view.getDrawingRect(mViewRect);
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        mViewRect.left = location[0];
        mViewRect.top = location[1];
        mViewRect.right = mViewRect.right + location[0];
        mViewRect.bottom = mViewRect.bottom + location[1];
        return mViewRect.contains(x,y);
    }

\color{#FF3030}{第二種}實(shí)現(xiàn)方式:直接使用WindowManager來添加對(duì)應(yīng)的布局募壕,這個(gè)也是不跟Acitivty綁定的全局彈窗,甚至在app退到后臺(tái)還可以繼續(xù)顯示语盈。當(dāng)然按照業(yè)務(wù)需求在必要的時(shí)候removeView舱馅。

核心代碼如下:

 systemService = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        final LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        layoutView = inflater.inflate(R.layout.fp_fpbphone_custom_alarm_toast, null);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            params.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
//這個(gè)地方一定要這樣設(shè)置,不然要么是布局之外不能接受事件刀荒,要么是布局里面和返回按鍵接收不到事件代嗤。
        params.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        params.gravity = Gravity.TOP | Gravity.LEFT;
        // 設(shè)置窗口寬度和高度
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.x = 50;
        systemService.addView(layoutView,params);

最后,有幾個(gè)需要注意的點(diǎn):
1.一定要設(shè)置權(quán)限缠借。

<!--    彈窗權(quán)限-->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

2.權(quán)限在6.0系統(tǒng)以上要手動(dòng)設(shè)置

  @RequiresApi(api = Build.VERSION_CODES.M)
    private void requestPermission() {
        if (!Settings.canDrawOverlays(this)) {
            //未授權(quán)限干毅,請(qǐng)求權(quán)限
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            intent.setData(Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent,0);
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泼返,隨后出現(xiàn)的幾起案子硝逢,更是在濱河造成了極大的恐慌,老刑警劉巖符隙,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趴捅,死亡現(xiàn)場離奇詭異,居然都是意外死亡霹疫,警方通過查閱死者的電腦和手機(jī)拱绑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丽蝎,“玉大人猎拨,你說我怎么就攤上這事膀藐。” “怎么了红省?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵额各,是天一觀的道長。 經(jīng)常有香客問我吧恃,道長虾啦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任痕寓,我火速辦了婚禮傲醉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘呻率。我一直安慰自己硬毕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布礼仗。 她就那樣靜靜地躺著吐咳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪元践。 梳的紋絲不亂的頭發(fā)上韭脊,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音卢厂,去河邊找鬼乾蓬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慎恒,可吹牛的內(nèi)容都是我干的任内。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼融柬,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼死嗦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粒氧,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤越除,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后外盯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摘盆,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年饱苟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了孩擂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡箱熬,死狀恐怖类垦,靈堂內(nèi)的尸體忽然破棺而出狈邑,到底是詐尸還是另有隱情,我是刑警寧澤蚤认,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布米苹,位于F島的核電站扮匠,受9級(jí)特大地震影響秘噪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜计雌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一陪汽、第九天 我趴在偏房一處隱蔽的房頂上張望亏较。 院中可真熱鬧,春花似錦掩缓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尘执,卻和暖如春舍哄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背誊锭。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工表悬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丧靡。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓蟆沫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親温治。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饭庞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345