国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android 項(xiàng)目必備(四十四)-->Android 實(shí)現(xiàn)懸浮窗

這篇具有很好參考價(jià)值的文章主要介紹了Android 項(xiàng)目必備(四十四)-->Android 實(shí)現(xiàn)懸浮窗。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前言

懸浮窗是一種比較常見(jiàn)的需求。例如把視頻通話界面縮小成一個(gè)懸浮窗,然后用戶可以在其他界面上處理事情。

本文將講解懸浮窗實(shí)現(xiàn)步驟、原理、實(shí)例代碼等

實(shí)現(xiàn)原理

1. WindowMananger 接口

Android 的界面繪制,都是通過(guò) WindowMananger 的服務(wù)來(lái)實(shí)現(xiàn)的。那么,既然要實(shí)現(xiàn)一個(gè)能夠在自身應(yīng)用以外的界面上的懸浮窗,我們就要利用 WindowManager 來(lái)實(shí)現(xiàn)。

(frameworks/base/core/java/android/view/WindowMananger.java)

@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
	...
}

WindowManager 實(shí)現(xiàn)了 ViewManager 接口,可以通過(guò)獲取 WINDOW_SERVICE 系統(tǒng)服務(wù)得到。而ViewManager 接口有 addView 方法,我們就是通過(guò)這個(gè)方法將懸浮窗控件加入到屏幕中去。

2. LayoutParam 設(shè)置

這里需要著重說(shuō)明的是 LayoutParam 里的 type 變量。這個(gè)變量是用來(lái)指定窗口類型的。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

具體實(shí)現(xiàn)

實(shí)現(xiàn)一個(gè)自動(dòng)輪播圖的懸浮窗。

1. 效果圖

android懸浮窗實(shí)現(xiàn),Android -- 項(xiàng)目必備,android,java,開(kāi)發(fā)語(yǔ)言

2. 聲明及申請(qǐng)權(quán)限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
@RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity {

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

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "授權(quán)失敗", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "授權(quán)成功", Toast.LENGTH_SHORT).show();
                startService(new Intent(MainActivity.this, FloatingImageDisplayService.class));
            }
        } 
    }
    
    public void startFloatingImageDisplayService(View view) {
        if (FloatingImageDisplayService.isStarted) {
            return;
        }
        if (!Settings.canDrawOverlays(this)) {
            Toast.makeText(this, "當(dāng)前無(wú)權(quán)限,請(qǐng)授權(quán)", Toast.LENGTH_SHORT);
            startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 1);
        } else {
            startService(new Intent(MainActivity.this, FloatingImageDisplayService.class));
        }
    }
}

3. 構(gòu)建懸浮窗需要的控件

image_display.xml文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-525236.html

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/image_display_imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

4. 將控件添加到WindowManager

@RequiresApi(api = Build.VERSION_CODES.M)
public class FloatingImageDisplayService extends Service {
    public static boolean isStarted = false;

    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;

    private View displayView;

    private int[] images;
    private int imageIndex = 0;

    private Handler changeImageHandler;

    @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 = 500;
        layoutParams.height = 500;
        layoutParams.x = 300;
        layoutParams.y = 300;

        images = new int[] {
                R.mipmap.image_01,
                R.mipmap.image_02,
                R.mipmap.image_03,
                R.mipmap.image_04,
                R.mipmap.image_05
        };

        changeImageHandler = new Handler(this.getMainLooper(), changeImageCallback);
    }



    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        showFloatingWindow();
        return super.onStartCommand(intent, flags, startId);
    }


    private void showFloatingWindow() {
        if (Settings.canDrawOverlays(this)) {
            LayoutInflater layoutInflater = LayoutInflater.from(this);
            displayView = layoutInflater.inflate(R.layout.image_display, null);
            displayView.setOnTouchListener(new FloatingOnTouchListener());
            ImageView imageView = displayView.findViewById(R.id.image_display_imageview);
            imageView.setImageResource(images[imageIndex]);
            windowManager.addView(displayView, layoutParams);

            changeImageHandler.sendEmptyMessageDelayed(0, 2000);
        }
    }

    private Handler.Callback changeImageCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == 0) {
                imageIndex++;
                if (imageIndex >= 5) {
                    imageIndex = 0;
                }
                if (displayView != null) {
                    ((ImageView) displayView.findViewById(R.id.image_display_imageview)).setImageResource(images[imageIndex]);
                }

                changeImageHandler.sendEmptyMessageDelayed(0, 2000);
            }
            return false;
        }
    };

    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:
                    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;
                default:
                    break;
            }
            return false;
        }
    }
}

到了這里,關(guān)于Android 項(xiàng)目必備(四十四)-->Android 實(shí)現(xiàn)懸浮窗的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Android - 使用GSY實(shí)現(xiàn)視頻播放和畫(huà)中畫(huà)懸浮窗

    Android - 使用GSY實(shí)現(xiàn)視頻播放和畫(huà)中畫(huà)懸浮窗

    0. 現(xiàn)完成功能: 懸浮窗區(qū)分橫屏豎屏兩種尺寸 懸浮窗可以在頁(yè)面上隨意拖動(dòng) 在播放視頻時(shí)按返回鍵/Home鍵/離開(kāi)當(dāng)前頁(yè)時(shí)觸發(fā)開(kāi)啟 懸浮窗顯示在退到后臺(tái)/在應(yīng)用內(nèi)/桌面 帶播放進(jìn)度開(kāi)啟懸浮窗,帶播放進(jìn)度回到應(yīng)用內(nèi)頁(yè)面 權(quán)限:每次開(kāi)啟前判斷有無(wú)權(quán)限,沒(méi)權(quán)限并且請(qǐng)求過(guò)

    2023年04月11日
    瀏覽(24)
  • 【Android從零單排系列四十八】《Android中自定義activity的實(shí)現(xiàn)方法》

    目錄 前言 一? activity介紹 二? activity的缺點(diǎn) 三? 自定義activity的步驟 四 自定義activity的demo 小伙伴們,在前面的文章中,我們談到了Android開(kāi)發(fā)中的自定義view的基本概念及方法等,本文我們實(shí)際舉例自定義一個(gè)activity。 Activity(活動(dòng))是Android應(yīng)用程序中的核心組件之一,它代

    2024年02月15日
    瀏覽(30)
  • 【Android從零單排系列四十九】《Android中自定義Fragment的實(shí)現(xiàn)方法》

    目錄 前言 一 ?Fragment介紹 二 ?Fragment的缺點(diǎn) 三? 自定義Fragment的步驟 四 自定義Fragment的demo 小伙伴們,在前面的文章中,我們談到了Android開(kāi)發(fā)中的自定義view的基本概念及方法等,本文我們實(shí)際舉例自定義一個(gè)Fragment。 Fragment是Android中一種用于構(gòu)建靈活和可重用界面組件的基

    2024年02月13日
    瀏覽(21)
  • Android 開(kāi)發(fā)必備知識(shí)點(diǎn)及面試題匯總(Android+Java+算法+性能優(yōu)化+四大組件……),騰訊安卓開(kāi)發(fā)面試

    Android 開(kāi)發(fā)必備知識(shí)點(diǎn)及面試題匯總(Android+Java+算法+性能優(yōu)化+四大組件……),騰訊安卓開(kāi)發(fā)面試

    5.請(qǐng)介紹下 AsyncTask的內(nèi)部實(shí)現(xiàn),適用的場(chǎng)景是 AsyncTask 內(nèi)部也是 Handler 機(jī)制來(lái)完成的,只不過(guò) Android 提供了執(zhí)行框架來(lái)提供線程池來(lái) 執(zhí)行相應(yīng)地任務(wù),因?yàn)榫€程池的大小問(wèn)題,所以 AsyncTask 只應(yīng)該用來(lái)執(zhí)行耗時(shí)時(shí)間較短的任務(wù), 比如 HTTP 請(qǐng)求,大規(guī)模的下載和數(shù)據(jù)庫(kù)的更改不

    2024年04月15日
    瀏覽(27)
  • android 懸浮窗 模擬微信通話返回桌面懸浮

    現(xiàn)有一款I(lǐng)M聊天需求,在通話頁(yè)面點(diǎn)擊縮小視圖或者Home鍵返回桌面,點(diǎn)擊懸浮窗回到通話頁(yè)面這樣一個(gè)需求。 權(quán)限 首先是權(quán)限的獲取,請(qǐng)注意,在Android 8.0及以上版本中,需要申請(qǐng)懸浮窗權(quán)限(SYSTEM_ALERT_WINDOW)才能顯示懸浮窗。你可以在應(yīng)用啟動(dòng)時(shí)請(qǐng)求該權(quán)限,或者引導(dǎo)用

    2024年02月01日
    瀏覽(14)
  • Android NestedScrollView懸浮固定頂部

    Android NestedScrollView懸浮固定頂部

    項(xiàng)目中有頁(yè)面涉及到多個(gè)元素組 需要NestedScrollView包裹來(lái)上下滑動(dòng) 接到需求 一些標(biāo)題在滑動(dòng)到頂部時(shí)需要置頂 我之前做過(guò)關(guān)于Android Behavior之ViewPager+Fragment+RecyclerView實(shí)現(xiàn)吸頂效果 大概就是這種效果 只不過(guò)這次是隨意的組件 比如 TextView 或布局組件 RelativeLayout 等 廢話不多說(shuō)來(lái)

    2024年01月24日
    瀏覽(13)
  • Android 應(yīng)用彈出懸浮窗

    Android 應(yīng)用彈出懸浮窗

    Android開(kāi)發(fā)者經(jīng)常遇到應(yīng)用想彈出懸浮窗的操作,而且有可能還想要高層級(jí)彈窗,就像ipone的浮標(biāo)touch一樣。android當(dāng)然也有類似的懸浮圖標(biāo),比如前些年我們的流量監(jiān)控提醒。 ?這里我們忽略UI美學(xué),簡(jiǎn)單記錄一下: 1、基本使用 它的基本使用步驟是不會(huì)變的,只是有時(shí)候我們

    2024年02月16日
    瀏覽(16)
  • 【從零開(kāi)始學(xué)習(xí)JAVA | 第四十四篇】TCP協(xié)議中的握手與揮手

    【從零開(kāi)始學(xué)習(xí)JAVA | 第四十四篇】TCP協(xié)議中的握手與揮手

    TCP(傳輸控制協(xié)議)作為計(jì)算機(jī)網(wǎng)絡(luò)中的重要協(xié)議,扮演著確保數(shù)據(jù)可靠傳輸?shù)慕巧?。在TCP的通信過(guò)程中,握手與揮手問(wèn)題是不可忽視的關(guān)鍵環(huán)節(jié)。握手是指在建立連接時(shí),客戶端與服務(wù)器相互確認(rèn)彼此的身份并同步參數(shù),確保雙方準(zhǔn)備就緒;而揮手則是在終止連接時(shí),雙方

    2024年02月11日
    瀏覽(88)
  • Android 點(diǎn)擊懸浮窗后臺(tái)啟動(dòng)Activity問(wèn)題及方案

    Android 點(diǎn)擊懸浮窗后臺(tái)啟動(dòng)Activity問(wèn)題及方案

    背景:開(kāi)啟懸浮窗,當(dāng)app進(jìn)入后臺(tái)后,點(diǎn)擊懸浮窗進(jìn)入固定頁(yè)面 問(wèn)題:當(dāng)app在后臺(tái)運(yùn)行時(shí),點(diǎn)擊懸浮窗,以下代碼不能拉起app,經(jīng)排查,部門手機(jī)需要開(kāi)啟后臺(tái)彈出界面權(quán)限 如圖? 不同的機(jī)型這個(gè)權(quán)限的名稱也不相同,要開(kāi)啟此權(quán)限,要跳轉(zhuǎn)的界面也不同,所以需要獲取不同機(jī)型的此頁(yè)面路

    2024年02月11日
    瀏覽(19)
  • android 12后WindowManager事件穿透類型懸浮窗無(wú)效問(wèn)題

    android 12后WindowManager事件穿透類型懸浮窗無(wú)效問(wèn)題

    筆記: 項(xiàng)目需要將一個(gè)懸浮窗WindowManager僅顯示view給用戶看,不可操作,將觸摸事件穿透到后面的窗口。WindowManager.LayoutParams代碼如下 在android12以下的機(jī)型中測(cè)試都沒(méi)問(wèn)題,觸摸事件可以穿透懸浮窗。但在android 12機(jī)型測(cè)試時(shí),觸摸事件無(wú)法穿透懸浮窗了。 查了android開(kāi)發(fā)者官

    2024年02月13日
    瀏覽(78)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包