91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kotlin如何實現Android系統懸浮窗

發布時間:2021-12-15 11:27:35 來源:億速云 閱讀:281 作者:iii 欄目:開發技術

本篇內容介紹了“Kotlin如何實現Android系統懸浮窗”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    Android 彈窗淺談

    我們知道 Android 彈窗中,有一類彈窗會在應用之外也顯示,這是因為他被申明成了系統彈窗,除此之外還有2類彈窗分別是:子彈窗應用彈窗

    應用彈窗:就是我們常規使用的 Dialog 之類彈窗,依賴于應用的 Activity;子彈窗:依賴于父窗口,比如 PopupWindow;系統彈窗:比如狀態欄、Toast等,本文所講的系統懸浮窗就是系統彈窗。

    系統懸浮窗具體實現

    權限申請

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

    代碼設計

    下面的包結構截圖,簡單展示了實現系統懸浮窗的代碼結構,更復雜的業務需要可在此基礎上進行擴展。

    Kotlin如何實現Android系統懸浮窗

    FloatWindowService:系統懸浮窗在此 Service 中彈出;

    FloatWindowManager:系統懸浮窗管理類;

    FloatLayout:系統懸浮窗布局;

    HomeKeyObserverReceiver:

    監聽 Home 鍵;

    FloatWindowUtils:系統懸浮窗工具類。

    具體實現

    FloatWindowService 類
    class FloatWindowService : Service() {
     
        private val TAG = FloatWindowService::class.java.simpleName
        private var mFloatWindowManager: FloatWindowManager? = null
        private var mHomeKeyObserverReceiver: HomeKeyObserverReceiver? = null
     
        override fun onCreate() {
            TLogUtils.i(TAG, "onCreate: ")
            mFloatWindowManager = FloatWindowManager(applicationContext)
            mHomeKeyObserverReceiver = HomeKeyObserverReceiver()
     
            registerReceiver(mHomeKeyObserverReceiver, IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
            mFloatWindowManager!!.createWindow()
        }
     
        override fun onBind(intent: Intent?): IBinder? {
            return null
        }
     
        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            return START_NOT_STICKY
        }
     
        override fun onDestroy() {
            TLogUtils.i(TAG, "onDestroy: ")
            mFloatWindowManager?.removeWindow()
            if (mHomeKeyObserverReceiver != null) {
                unregisterReceiver(mHomeKeyObserverReceiver)
            }
        }
     
    }
    FloatWindowManager 類

    包括系統懸浮窗的創建、顯示、銷毀(以及更新)。

     public void addView(View view, ViewGroup.LayoutParams params); // 添加 View 到 Window
    public void updateViewLayout(View view, ViewGroup.LayoutParams params); //更新 View 在 Window 中的位置
    public void removeView(View view); //刪除 View
    FloatWindowManager 類代碼
    class FloatWindowManager constructor(context: Context) {
     
        var isShowing = false
        private val TAG = FloatWindowManager::class.java.simpleName
        private var mContext: Context = context
        private var mFloatLayout = FloatLayout(mContext)
        private var mLayoutParams: WindowManager.LayoutParams? = null
        private var mWindowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
     
        fun createWindow() {
            TLogUtils.i(TAG, "createWindow: start...")
            // 對象配置操作使用apply,額外的處理使用also
            mLayoutParams = WindowManager.LayoutParams().apply {
                type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    // Android 8.0以后需要使用TYPE_APPLICATION_OVERLAY,不允許使用以下窗口類型來在其他應用和窗口上方顯示提醒窗口:TYPE_PHONE、TYPE_PRIORITY_PHONE、TYPE_SYSTEM_ALERT、TYPE_SYSTEM_OVERLAY、TYPE_SYSTEM_ERROR。
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
                } else {
                    // 在Android 8.0之前,懸浮窗口設置可以為TYPE_PHONE,這種類型是用于提供用戶交互操作的非應用窗口。
                    // 在API Level  = 23的時候,需要在Android Manifest.xml文件中聲明權限SYSTEM_ALERT_WINDOW才能在其他應用上繪制控件
                    WindowManager.LayoutParams.TYPE_PHONE
                }
                // 設置圖片格式,效果為背景透明
                format = PixelFormat.RGBA_8888
                // 設置浮動窗口不可聚焦(實現操作除浮動窗口外的其他可見窗口的操作)
                flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                // 調整懸浮窗顯示的停靠位置為右側置頂
                gravity = Gravity.TOP or Gravity.END
                width = 800
                height = 200
                x = 20
                y = 40
            }
     
            mWindowManager.addView(mFloatLayout, mLayoutParams)
            TLogUtils.i(TAG, "createWindow: end...")
            isShowing = true
        }
     
        fun showWindow() {
            TLogUtils.i(TAG, "showWindow: isShowing = $isShowing")
            if (!isShowing) {
                if (mLayoutParams == null) {
                    createWindow()
                } else {
                    mWindowManager.addView(mFloatLayout, mLayoutParams)
                    isShowing = true
                }
            }
        }
     
        fun removeWindow() {
            TLogUtils.i(TAG, "removeWindow: isShowing = $isShowing")
            mWindowManager.removeView(mFloatLayout)
            isShowing = false
        }
     
    }
    FloatLayout 類及其 Layout

    系統懸浮窗自定義View:FloatLayout

    class FloatLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0) :
        ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) {
     
        private var mTime: TCLTextView
        private var mDistance: TCLTextView
        private var mSpeed: TCLTextView
        private var mCalories: TCLTextView
     
        init {
            val view = LayoutInflater.from(context).inflate(R.layout.do_exercise_view_float_layout, this, true)
            mTime = view.findViewById(R.id.float_layout_tv_time)
            mDistance = view.findViewById(R.id.float_layout_tv_distance)
            mSpeed = view.findViewById(R.id.float_layout_tv_speed)
            mCalories = view.findViewById(R.id.float_layout_tv_calories)
        }
     
    }

    布局文件:float_layout_tv_time

    HomeKeyObserverReceiver 類
    class HomeKeyObserverReceiver : BroadcastReceiver() {
     
        override fun onReceive(context: Context?, intent: Intent?) {
            try {
                val action = intent!!.action
                val reason = intent.getStringExtra("reason")
                TLogUtils.d(TAG, "HomeKeyObserverReceiver: action = $action,reason = $reason")
                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS == action && "homekey" == reason) {
                    val keyCode = intent.getIntExtra("keycode", KeyEvent.KEYCODE_UNKNOWN)
                    TLogUtils.d(TAG, "keyCode = $keyCode")
                    context?.stopService(Intent(context, FloatWindowService::class.java))
                }
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
        }
     
        companion object {
            private val TAG = HomeKeyObserverReceiver::class.java.simpleName
        }
     
    }
    FloatWindowUtils 類
    object FloatWindowUtils {
     
        const val REQUEST_FLOAT_CODE = 1000
        private val TAG = FloatWindowUtils::class.java.simpleName
     
        /**
         * 判斷Service是否開啟
         */
        fun isServiceRunning(context: Context, ServiceName: String): Boolean {
            if (TextUtils.isEmpty(ServiceName)) {
                return false
            }
            val myManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            val runningService = myManager.getRunningServices(1000) as ArrayList<ActivityManager.RunningServiceInfo>
            runningService.forEach {
                if (it.service.className == ServiceName) {
                    return true
                }
            }
            return false
        }
     
        /**
         * 檢查懸浮窗權限是否開啟
         */
        @SuppressLint("NewApi")
        fun checkSuspendedWindowPermission(context: Activity, block: () -> Unit) {
            if (commonROMPermissionCheck(context)) {
                block()
            } else {
                Toast.makeText(context, "請開啟懸浮窗權限", Toast.LENGTH_SHORT).show()
                context.startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply {
                    data = Uri.parse("package:${context.packageName}")
                }, REQUEST_FLOAT_CODE)
            }
        }
     
        /**
         * 判斷懸浮窗權限權限
         */
        fun commonROMPermissionCheck(context: Context?): Boolean {
            var result = true
            if (Build.VERSION.SDK_INT >= 23) {
                try {
                    val clazz: Class<*> = Settings::class.java
                    val canDrawOverlays = clazz.getDeclaredMethod("canDrawOverlays", Context::class.java)
                    result = canDrawOverlays.invoke(null, context) as Boolean
                } catch (e: Exception) {
                    TLogUtils.e(TAG, e)
                }
            }
            return result
        }
     
    }

    “Kotlin如何實現Android系統懸浮窗”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    龙海市| 宝鸡市| 侯马市| 泗水县| 龙游县| 萨嘎县| 昂仁县| 边坝县| 栾城县| 滦平县| 水城县| 兰西县| 咸阳市| 成武县| 旺苍县| 山东| 磐石市| 淅川县| 罗定市| 若尔盖县| 乌什县| 梨树县| 卫辉市| 恩施市| 鹤山市| 漳州市| 甘南县| 禄劝| 隆林| 平武县| 新宁县| 衢州市| 武义县| 绥化市| 彭阳县| 冕宁县| 凌海市| 潞西市| 江山市| 长寿区| 桃园县|