返回顶部
首页 > 资讯 > 移动开发 >Android实现悬浮窗的简单方法实例
  • 642
分享到

Android实现悬浮窗的简单方法实例

2024-04-02 19:04:59 642人浏览 安东尼
摘要

目录1. 前言2.原理3.具体实现3.1浮窗布局3.2 悬浮窗的实现1. 使用服务Service2. 获取WindowManager并设置LayoutParams3. 创建View并

1. 前言

现在很多应用都有小悬浮窗的功能,比如看直播的时候,通过Home键返回桌面,直播的小窗口仍可以在屏幕上显示。下面将介绍下悬浮窗的的一种简单实现方式。

2.原理

Window我们应该很熟悉,它是一个接口类,具体的实现类为PhoneWindow,它可以对View进行管理。WindowManager是一个接口类,继承自ViewManager,从名称就知道它是用来管理Window的,它的实现类是WindowManagerImpl。如果我们想要对Window(View)进行添加、更新和删除操作就可以使用WindowManager,WindowManager会将具体的工作交由WindowManagerService处理。这里我们只需要知道WindowManager能用来管理Window就好。

WindowManager是一个接口类,继承自ViewManager,ViewManager中定义了3个方法,分布用来添加、更新和删除View,如下所示:


public interface ViewManager {
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

WindowManager也继承了这些方法,而这些方法传入的参数都是View类型,说明了Window是以View的形式存在的。

3.具体实现

3.1浮窗布局

悬浮窗的简易布局如下的可参考下面的layout_floating_window.xml文件。顶层深色部分的FrameLayout布局是用来实现悬浮窗的拖拽功能的,点击右上角ImageView可以实现关闭悬浮窗,剩下区域显示内容,这里只是简单地显示文本内容,不做复杂的东西,故只设置TextView。


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

    <FrameLayout
        android:id="@+id/layout_drag"
        android:layout_width="match_parent"
        android:layout_height="15dp"
        android:background="#DDDddd">
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/iv_close"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_gravity="end"
            android:src="@drawable/img_delete"/>
    </FrameLayout>

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:background="#eeeeee"
        android:scrollbars="vertical"/>
</LinearLayout>

3.2 悬浮窗的实现

1. 使用服务Service

Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件,可由其他应用组件启动,而且即使用户切换到其他应用,仍将在后台继续运行。要保证应用在后台时,悬浮窗仍然可以正常显示,所以这里可以使用Service。

2. 获取WindowManager并设置LayoutParams


private lateinit var windowManager: WindowManager
private lateinit var layoutParams: WindowManager.LayoutParams
override fun onCreate() {
    // 获取WindowManager
    windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
    layoutParams = WindowManager.LayoutParams().apply {
        // 实现在其他应用和窗口上方显示浮窗
        type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            WindowManager.LayoutParams.TYPE_PHONE
        }
        fORMat = PixelFormat.RGBA_8888
        // 设置浮窗的大小和位置
        gravity = Gravity.START or Gravity.TOP
        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        width = 600
        height = 600
        x = 300
        y = 300
    }
}

3. 创建View并添加到WindowManager


private lateinit var floatingView: View
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    if (Settings.canDrawOverlays(this)) {
        floatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating_window.xml, null)
        windowManager.addView(floatingView, layoutParams)
    }  
    return super.onStartCommand(intent, flags, startId)
}

4. 实现悬浮窗的拖拽和关闭功能


// 浮窗的坐标
private var x = 0
private var y = 0

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {   
    if (Settings.canDrawOverlays(this)) {
    floatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating_window.xml, null)
    windowManager.addView(floatingView, layoutParams)

    // 点击浮窗的右上角关闭按钮可以关闭浮窗
    floatingView.findViewById<AppCompatImageView>(R.id.iv_close).setOnClickListener {
     windowManager.removeView(floatingView)
    }
    // 实现浮窗的拖动功能, 通过改变layoutParams来实现
    floatingView.findViewById<AppCompatImageView>(R.id.layout_drag).setOnTouchListener { v, event ->
     when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                x = event.rawX.toInt()
                y = event.rawY.toInt()
            }
            MotionEvent.ACTION_MOVE -> {
                val currentX = event.rawX.toInt()
                val currentY = event.rawY.toInt()
                val offsetX = currentX - x
                val offsetY = currentY - y
                x = currentX
                y = currentY
                layoutParams.x = layoutParams.x + offsetX
                layoutParams.y = layoutParams.y + offsetY
                // 更新floatingView
                windowManager.updateViewLayout(floatingView, layoutParams)
            }
        }
        true
    }
    return super.onStartCommand(intent, flags, startId)
}

5. 利用广播进行通信


private var receiver: MyReceiver? = null
override fun onCreate() {
    // 注册广播
    receiver = MyReceiver()
    val filter = IntentFilter()
    filter.addAction("android.intent.action.MyReceiver")
    reGISterReceiver(receiver, filter)
}

inner class MyReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val content = intent.getStringExtra("content") ?: ""

        // 通过Handler更新UI
        val message = Message.obtain()
        message.what = 0
        message.obj = content
        handler.sendMessage(message)
    }
}

val handler = Handler(this.mainLooper) { msg ->
    tvContent.text = msg.obj as String
    false
}

可以在Activity中通过广播给Service发送信息


fun sendMessage(view: View?) {
    Intent("android.intent.action.MyReceiver").apply {
        putExtra("content", "Hello, World!")
        sendBroadcast(this)
    }
}

6. 设置权限

悬浮窗的显示需要权限,在AndroidManefest.xml中添加:


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

此外,还要通过Settings.ACTION_MANAGE_OVERLAY_PERMISSION来让动态设置权限,在Activity中设置。


// MainActivity.kt
fun startWindow(view: View?) {
    if (!Settings.canDrawOverlays(this)) {
        startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")), 0)
    } else {
        startService(Intent(this@MainActivity, Floatingwindowservice::class.java))
    }
}
​
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 0) {
        if (Settings.canDrawOverlays(this)) {
            Toast.makeText(this, "悬浮窗权限授权成功", Toast.LENGTH_SHORT).show()
            startService(Intent(this@MainActivity, FloatingWindowService::class.java))
        }
    }
}

3.3 完整代码


class FloatingWindowService : Service() {
    private lateinit var windowManager: WindowManager
    private lateinit var layoutParams: WindowManager.LayoutParams
    private lateinit var tvContent: AppCompatTextView
    private lateinit var handler: Handler

    private var receiver: MyReceiver? = null
    private var floatingView: View? = null
    private val stringBuilder = StringBuilder()

    private var x = 0
    private var y = 0

    // 用来判断floatingView是否attached 到 window manager,防止二次removeView导致崩溃
    private var attached = false

    override fun onCreate() {
        super.onCreate()
        // 注册广播
        receiver = MyReceiver()
        val filter = IntentFilter()
        filter.addAction("android.intent.action.MyReceiver")
        registerReceiver(receiver, filter);

        // 获取windowManager并设置layoutParams
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
        layoutParams = WindowManager.LayoutParams().apply {
            type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            } else {
                WindowManager.LayoutParams.TYPE_PHONE
            }
            format = PixelFormat.RGBA_8888
//            format = PixelFormat.TRANSPARENT
            gravity = Gravity.START or Gravity.TOP
            flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            width = 600
            height = 600
            x = 300
            y = 300
        }
        handler = Handler(this.mainLooper) { msg ->
            tvContent.text = msg.obj as String
            // 当文本超出屏幕自动滚动,保证文本处于最底部
            val offset = tvContent.lineCount * tvContent.lineHeight
            floatingView?.apply {
                if (offset > height) {
                    tvContent.scrollTo(0, offset - height)
                }
            }
            false
        }
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (Settings.canDrawOverlays(this)) {
            floatingView = LayoutInflater.from(this).inflate(R.layout.layout_show_log, null)
            tvContent = floatingView!!.findViewById(R.id.tv_log)
            floatingView!!.findViewById<AppCompatImageView>(R.id.iv_close).setOnClickListener {
                stringBuilder.clear()
                windowManager.removeView(floatingView)
                attached = false
            }
            // 设置TextView滚动
            tvContent.movementMethod = ScrollingMovementMethod.getInstance()

            floatingView!!.findViewById<FrameLayout>(R.id.layout_drag).setOnTouchListener { v, event ->
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        x = event.rawX.toInt()
                        y = event.rawY.toInt()
                    }
                    MotionEvent.ACTION_MOVE -> {
                        val currentX = event.rawX.toInt()
                        val currentY = event.rawY.toInt()
                        val offsetX = currentX - x
                        val offsetY = currentY - y
                        x = currentX
                        y = currentY
                        layoutParams.x = layoutParams.x + offsetX
                        layoutParams.y = layoutParams.y + offsetY
                        windowManager.updateViewLayout(floatingView, layoutParams)
                    }
                }
                true
            }

            windowManager.addView(floatingView, layoutParams)
            attached = true
        }
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        // 注销广播并删除浮窗
        unregisterReceiver(receiver)
        receiver = null
        if (attached) {
            windowManager.removeView(floatingView)
        }
    }

    inner class MyReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val content = intent.getStringExtra("content") ?: ""
            stringBuilder.append(content).append("\n")
            val message = Message.obtain()
            message.what = 0
            message.obj = stringBuilder.toString()
            handler.sendMessage(message)
        }
    }
}

4. 总结

以上就是Android悬浮窗的一个简单实现方式。如果需要实现其他复杂一点的功能,比如播放视频,也可以在此基础上完成。

到此这篇关于Android实现悬浮窗的简单方法的文章就介绍到这了,更多相关Android实现悬浮窗内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Android实现悬浮窗的简单方法实例

本文链接: https://lsjlt.com/news/136595.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android实现悬浮窗的简单方法实例
    目录1. 前言2.原理3.具体实现3.1浮窗布局3.2 悬浮窗的实现1. 使用服务Service2. 获取WindowManager并设置LayoutParams3. 创建View并...
    99+
    2024-04-02
  • Android应用内悬浮窗Activity的简单实现
    目录前言缩放方法悬浮样式点击穿透空白移动悬浮窗例子的完整代码styles.xmllayoutactivity运行效果小结前言 悬浮窗是一种比较常见的需求。例如把视频通话界面缩小成一个...
    99+
    2024-04-02
  • Android实现圆形菜单悬浮窗
    序言 Android悬浮窗的实现,主要有四个步骤: 1. 声明及申请权限2. 构建悬浮窗需要的控件3. 将控件添加到WindowManager4. 必要时更新WindowManage...
    99+
    2024-04-02
  • android编程实现悬浮窗体的方法
    本文实例讲述了android编程实现悬浮窗体的方法。分享给大家供大家参考,具体如下: 突然对悬浮窗体感兴趣,查资料做了个小Demo,效果是点击按钮后,关闭当前Activity,...
    99+
    2022-06-06
    方法 窗体 Android
  • Android实现悬浮窗效果
    本文实例为大家分享了Android实现悬浮窗效果的具体代码,供大家参考,具体内容如下 一、权限: <uses-permission android:name="android....
    99+
    2024-04-02
  • Android悬浮窗如何实现
    小编给大家分享一下Android悬浮窗如何实现,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!效果如下:显示浮窗原生ViewManager接口提供了向窗口添加并操纵...
    99+
    2023-06-04
  • Android应用内悬浮窗的实现方案示例
    1、悬浮窗的基本介绍悬浮窗,大家应该也不陌生,凌驾于应用之上的一个小弹窗,实现上很简单,就是添加一个系统级别的窗口,Android中通过WindowManagerService( WMS)来管理所有的窗口,对于WMS来说,管你是Activi...
    99+
    2023-05-30
    android
  • Android超简单悬浮窗使用教程
    完全自定义悬浮窗,保证100%学会的超简单悬浮窗 先看看效果图:                 图...
    99+
    2024-04-02
  • Android中悬浮窗口的实现原理实例分析
    本文实例讲述了Android中悬浮窗口的实现原理。分享给大家供大家参考。具体如下: 用了我一个周末的时间,个中愤懑就不说了,就这个问题,我翻遍全球网络没有一篇像样的资料,现在将...
    99+
    2022-06-06
    悬浮窗口 Android
  • Android无障碍全局悬浮窗实现示例
    目录无障碍添加 UI配置分析TypeFlagLayoutInDisplayCutoutModeAndroid 无障碍的全局悬浮窗可以在屏幕上添加 UI 供用户进行快捷操作,可以展示在...
    99+
    2024-04-02
  • Android视频悬浮窗口实现的示例代码
    前言 本文例子实现了点击显示悬浮窗口,同时窗口可播放视频,拖动位置,点击关闭及返回 APP 页面,通过例子来讲述悬浮窗口实现原理及细节处理,效果图如下所示: 悬浮窗口.gif...
    99+
    2022-06-06
    悬浮窗口 示例 Android
  • Android悬浮窗效果怎么实现
    要实现Android的悬浮窗效果,可以采用以下几种方法: 使用系统提供的WindowManager类来创建一个悬浮窗口。可以通过...
    99+
    2023-10-22
    Android
  • C#实现悬浮窗口的方法详解
    目录一 悬浮窗口二 创建悬浮窗口1 实现细节2 细节三 圆形背景一 悬浮窗口 特点: ① 窗口一般较小,有时为不规则背景; ② 置顶显示; ③ 窗口支持拖动; ④ 一般用于程序状态显...
    99+
    2022-12-21
    C#悬浮窗口 C# 窗口
  • Android悬浮窗屏蔽悬浮窗外部所有的点击事件的实例代码
    Android可以在所有应用上方添加View,就是给WindowManager添加一个View,在创建的View的时候可以给这个View设置LayoutParams(andro...
    99+
    2022-06-06
    事件 android悬浮窗 Android
  • Kotlin如何实现Android系统悬浮窗
    本篇内容介绍了“Kotlin如何实现Android系统悬浮窗”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Android 弹窗浅谈我们知道 ...
    99+
    2023-06-22
  • Android WindowManger实现桌面悬浮窗功能
    目录效果图使用WindowManager实现分析问题参考如果想实现一个在桌面显示的悬浮窗,用Dialog、PopupWindow、Toast等已经不能实现了,他们基本都是在Activ...
    99+
    2023-05-18
    Android桌面悬浮窗 Android WindowManger悬浮窗
  • Kotlin实现Android系统悬浮窗详解
    目录Android 弹窗浅谈系统悬浮窗具体实现权限申请代码设计具体实现FloatWindowService 类FloatWindowManager 类FloatWindowManag...
    99+
    2024-04-02
  • Android可拖动悬浮窗怎么实现
    要实现在Android中可拖动的悬浮窗,可以按照以下步骤进行:1. 创建一个自定义的`FloatingView`类来实现悬浮窗的视图...
    99+
    2023-08-16
    Android
  • Android实现桌面悬浮窗、蒙板效果实例代码
    现在很多安全类的软件,比如360手机助手,百度手机助手等等,都有一个悬浮窗,可以飘浮在桌面上,方便用户使用一些常用的操作。 今天这篇文章,就是介绍如何实现桌面悬浮窗效果的。 首...
    99+
    2022-06-06
    Android
  • jquery插件实现悬浮菜单的方法
    这篇文章给大家分享的是有关jquery插件实现悬浮菜单的方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。jquery是什么jquery是一个简洁而快速的JavaScript库,它具有独特的链式语法和短小清晰的多...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作