Service: 三、小窗口(浮窗) 播放视频

Android视频悬浮窗口实现 前言 本文例子实现了点击显示悬浮窗口,同时窗口可播放视频,拖动位置,点击关闭及返回APP页面,通过例子来讲述悬浮窗口实现原理及细节处理,效果图如下所示: 原理 WindowManager对View视图进行添加、移除、更新处理; WindowManager.LayoutParams对窗口参数进行一系列设置。 实现 首先,需要添加相对应悬浮窗权限: <uses-permission a... 阅读详情


前言

本篇以简单的浮窗视频为例, 练习 Service, 浮窗, MediaPlayer视频播放等;

本篇涉及内容:

  • Service 的基本用法;
  • MediaPlayer 播放本地视频
  • 通过 WindowManager 添加浮窗
  • Android Result API 自定义协议类, 校验浮窗权限

一、先来张效果图


在这里插入图片描述

二、使用步骤

1.配置清单文件

<!-- SD卡读写权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<!-- 8.0 以上 前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<!-- 悬浮窗权限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<application
	...
	<!-- 读取本地文件需要 -->
	 android:requestLegacyExternalStorage="true" >
	
	<!-- 自定义的视频浮窗 Service -->
	<service android:name=".test.textservice.VideoFloatingService"/>

2.编写 Service

这次的 Service 并没有 上一篇 简单的音乐播放器 中的 Service 复杂;
只需要初始化 MediaPlayer, 播放视频. 添加悬浮窗. 以及内部简单的控制逻辑;

class VideoFloatingService: Service() {
    private val TAG = "VideoFloatingService"

    private lateinit var windowManager: WindowManager
    private lateinit var layoutParams: WindowManager.LayoutParams

    private lateinit var binding: ViewVideoFloatingBinding
    private lateinit var mediaPlayer: MediaPlayer

    override fun onCreate() {
        super.onCreate()
        init()  // 初始化播放器
        showFloatingWindow()    // 添加浮窗
    }

    override fun onBind(intent: Intent?): IBinder? = null

    private fun showFloatingWindow() {
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager

        // 初始化浮窗 layoutParams
        layoutParams = WindowManager.LayoutParams().also {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                it.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            } else {
                it.type = WindowManager.LayoutParams.TYPE_PHONE
            }

            it.format = PixelFormat.RGBA_8888
            it.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

            // 浮窗位置和尺寸, 偏移量等
            it.gravity = Gravity.CENTER_VERTICAL or Gravity.START
            it.width = WindowManager.LayoutParams.WRAP_CONTENT
            it.height = WindowManager.LayoutParams.WRAP_CONTENT
            it.x = 0
            it.y = 0
        }

        // 初始化浮窗布局, 为播放按钮添加事件; 为整个浮窗添加触摸监听(满足拖动, 点击等)
        binding = ViewVideoFloatingBinding.inflate(LayoutInflater.from(this))
        binding.ivPlay.setOnClickListener {
            binding.ivPlay.setImageResource(if(mediaPlayer.isPlaying){
                mediaPlayer.pause()
                R.mipmap.video_icon_play
            }else{
                mediaPlayer.start()
                R.mipmap.video_icon_suspend
            })
        }
        // 添加拖拽事件
        binding.root.setOnTouchListener(FloatingListener())

        // 要等 SurfaceHolder Created
        binding.svVideo.holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                mediaPlayer.setDisplay(binding.svVideo.holder)
            }
            override fun surfaceChanged(s: SurfaceHolder, f: Int, w: Int, h: Int ) {}
            override fun surfaceDestroyed(holder: SurfaceHolder) {}
        })

        // 添加浮窗
        windowManager.addView(binding.root, layoutParams)
    }

    private fun init() {
        mediaPlayer = MediaPlayer().also {
            it.isLooping = true // 循环播放

            val file = File(Environment.getExternalStorageDirectory(),"big_buck_bunny.mp4")
            it.setDataSource(file.path)

            it.prepareAsync()
            it.setOnPreparedListener {
                mediaPlayer.start()
            }
        }
    }

    override fun onDestroy() {
        mediaPlayer.stop()
        mediaPlayer.release()
        windowManager.removeView(binding.root)
        super.onDestroy()
    }

    inner class FloatingListener: View.OnTouchListener{
        private var x = 0   // 当前位置值
        private var y = 0
        private var cx = 0  // 点击初始值;
        private var cy = 0
        private var checkClick: Boolean = false

        @SuppressLint("ClickableViewAccessibility")
        override fun onTouch(v: View?, event: MotionEvent?): Boolean {
            when(event?.action){
                MotionEvent.ACTION_DOWN -> {
                    checkClick = true
                    cx = event.rawX.toInt()
                    cy = event.rawY.toInt()
                    x = cx
                    y = cy
                }
                MotionEvent.ACTION_MOVE -> {
                    val nowX = event.rawX.toInt()
                    val nowY = event.rawY.toInt()
                    val movedX = nowX - x
                    val movedY = nowY - y
                    x = nowX
                    y = nowY
                    layoutParams.let {
                        it.x = it.x + movedX
                        it.y = it.y + movedY
                    }

                    // 更新悬浮窗控件布局
                    windowManager.updateViewLayout(binding.root, layoutParams)

                    if (checkClick && (abs(x - cx) >= 5 || abs(y - cy) >= 5)) {
                        checkClick = false
                    }
                }
                MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                    if (checkClick && abs(cx - event.rawX.toInt()) < 5 && abs(cy - event.rawY.toInt()) < 5) {
                        // 判断为 浮窗点击事件;  控制播放按钮显隐;
                        if(binding.ivPlay.visibility == View.VISIBLE){
                            binding.ivPlay.visibility = View.GONE
                        }else{
                            binding.ivPlay.visibility = View.VISIBLE
                            binding.ivPlay.setImageResource(if(mediaPlayer.isPlaying){
                                R.mipmap.video_icon_suspend
                            } else {
                                R.mipmap.video_icon_play
                            })
                        }
                    }
                    checkClick = false
                }
            }
            return true
        }
    }
}

代码看起来不少, 但逻辑却很简单; 总体来看只有 初始化播放器, 添加浮窗, 添加触摸监听 等;


3. Activity

Activity 就很简单了, 先校验或请求一下权限. 然后直接启动 Service 就完事了;

// 点击事件
fun onClick(v: View) {
   when(v.id){
       R.id.tv_one -> {
           startFloatingWindow()	// 检验权限后 开启Service
       }
       R.id.tv_two -> {
           stopService(Intent(this, VideoFloatingService::class.java))
       }
   }
}

private fun startFloatingWindow() {
	// Android Result Api 的方式, 请求权限
    launcher2.launch(null)  
}

private val launcher2 = registerForActivityResult(RequestFloating(this)) {
    if(it){
    	// toast("") 这是 kotlin 自定义的扩展函数. 
        toast("有权限")	
        // 有了权限, 直接启动 Service 即可
        startService(Intent(this, VideoFloatingService::class.java))
    }else{
        toast("授权失败")
    }
}

4.请求权限

这是 俺自定义的 协议类; 有权限时 同步响应回调; 没有权限, 则跳转开启权限的页面;

class RequestFloating(val context: Context): ActivityResultContract<Unit, Boolean>(){
    @RequiresApi(Build.VERSION_CODES.M)
    override fun createIntent(context: Context, input: Unit?) = Intent().also {
            it.action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION
            it.data = Uri.parse("package:${context.packageName}")
        }

    override fun getSynchronousResult(context: Context, input: Unit?): SynchronousResult<Boolean>? {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {
            null
        } else {
            SynchronousResult(true)
        }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Boolean{
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(context)
    }
}

不了解 Android Result Api 的小伙伴可以看我这篇文章: Android Result API

当然也可以用下面这段代码:

//检查悬浮窗权限,小于6.0系统不需要权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
     Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
     intent.setData(Uri.parse("package:" + getPackageName()));
     startActivityForResult(intent, 100);
 }else{
     //已有权限
 }

这种. 还得重写 onActivityResult; 但是 onActivityResult 中并没有结果, 需要自己再判断一遍


5.浮窗的页面贴一下

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <SurfaceView
            android:id="@+id/sv_video"
            android:layout_width="180dp"
            android:layout_height="108dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>
        <ImageView
            android:id="@+id/iv_play"
            style="@style/img_wrap"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/video_icon_play"
            android:visibility="gone"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Activity 的页面就不贴了; 就俩按钮.
至此, 简单的视频浮窗播放 Service 完成 😀


三、画中画

博主本想在下一篇文章中 用画中画实现视频浮窗, 但发现写不出什么东西.
这里干脆只把关键代码帖一帖吧. 就当笔记了.

推荐文章:
官方文档 - 画中画支持

1.清单文件配置

<!-- android:supportsPictureInPicture="true" 是关键代码 - 开启画中画支持 -->
<activity android:name=".test.textservice.VideoDetailActivity"
    android:launchMode="singleTask"
    android:resizeableActivity="true"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"/>

2.进入画中画模式

 /**
  *进入画中画模式
  */
private var mPictureInPictureParamsBuilder: PictureInPictureParams.Builder? = null
private fun enterPiPMode() {
	// 
    // 低内存设备可能无法使用画中画模式。 进行检查以确保可以使用画中画。
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
        packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
        if (mPictureInPictureParamsBuilder == null) {
            mPictureInPictureParamsBuilder = PictureInPictureParams.Builder()
        }
        // 这是设置窗口宽高比例;  纵横比不能太极端(必须在0.418410和2.390000之间)。
        val aspectRatio = Rational(binding.svVideo.width, binding.svVideo.height)
        mPictureInPictureParamsBuilder?.setAspectRatio(aspectRatio)
        
        //进入pip模式
        enterPictureInPictureMode(mPictureInPictureParamsBuilder!!.build())
    }
}

3.在Activity中监听 PIP模式的切换

override fun onPictureInPictureModeChanged(
    isInPictureInPictureMode: Boolean,
    newConfig: Configuration?
) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
    if (isInPictureInPictureMode) {
        // Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
        // 隐藏多余 View ...
    } else {
        // Restore the full-screen UI.
        // 恢复隐藏的 View ...
    }
}

需要注意, 启动画中画模式时, Activity 生命周期是处于 paused 状态. 所以控制食品播放和暂停 可以放在 onStart() onStop() 中

画中画模式中, 事件是传不到 Activity 中的, 所以想要自定义窗口操作的UI, 需要额外处理.


总结

新手还是建议 自己把代码敲一下. 涉及的东西还是不少的. 至于视频播放, 博主会在下一篇文章中, 用画中画.. 好吧不用了

上一篇: Service: 二、简单的音乐播放器
下一篇: WorkManager笔记: 一、基础入门

DAC60501与STM32的I2C通信实战:从寄存器配置到电压输出 本文详细介绍了如何使用STM32通过I2C通信驱动DAC60501数模转换器,实现精确的模拟电压输出。内容涵盖从硬件连接到软件模拟I2C驱动编写,再到DAC寄存器配置与电压计算的全流程实战指南,并提供了关键的驱动实例代码和常见问题调试技巧,帮助开发者快速掌握这一嵌入式开发中的实用技能。 阅读详情

相关推荐

浪涌电流测试仪的工作原理

浪涌电流脉冲形成的开始由同步电路 13 确定,该同步电路 13 发送命令以打开和第二开关 10 和 11,向发生器 14 发送控制命令以生成被测半导体器件 5 的控制信号和参考信号整形器 9 的触发脉冲。电流源的功率输出并联连接,以对流经被测半导体样品的电流求和。此外,使用数字控制扩展了测试仪的功能,能够产生各种形状的电流脉冲,例如梯形电流脉冲,以估计被测晶闸管的导通状态扩展时间。由于晶体管3的栅极是连接的,并且平衡电阻4包含在晶体管3的源中,因此通过每个晶体管3的电流脉冲大致相同,并重复参考信号的形状。

Jesse0257的博客 1255

实现音频播放悬浮窗的服务services

FileVideoPlayService 实现功能,通过传递url,将url的代码进行播放,同时悬浮窗能够实现上下左右移动,在原有的基础上修改一下。先说明下,实现悬浮窗窗的代码我是借鉴别人的代码,但是我找不到他的链接,知道可以联系一下。

qq_51108920的博客 362

NFS服务器配置与autofs自动挂载

NFS服务器配置autofs自动挂载 环境: hostname ip OS server 192.168.220.138 centos7 client 192.168.220.139 centos7 一、NFS概述 NFS(Network File System)网络文件系统。最大功能就是通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。 二、端口 [root@se...

DoloresOOO的博客 1026

Android: Service中创建窗口显示(TYPE_SYSTEM_ALERT, TYPE_SYSTEM_OVERLAY)

有时候需要在显示UI的时候不中断原来的Activity 比如在播放视频时或者玩游戏时,需要显示某个菜单(可以是系统提示,或类似于TV菜单) 显然用Activity来做是不行的,因为新Activity启动的时候会把原来的Activity pause掉 怎么做呢,可以参考系统电量提示窗口或statusbar那样在service中启动窗口 新窗口将会出现在UI最上层,但不会中断原来的Activi...

webcenterol 694

Dify平台+Excel批量分析实战:5分钟搞定大模型数据处理(附完整代码)

本文详细介绍了如何利用Dify平台的数据集功能,结合Excel和Python脚本,快速构建大模型批量数据处理流水线。通过实战案例演示,读者可在5分钟内完成客户反馈情感分析、产品文案生成等任务,实现从原始数据到结构化洞察的高效转化,极大提升工作效率。

3a9bq4r8t2y的博客 316

Wider Face+YOLOV7人脸检测

使用Wider Face数据集训练YOLOV7

chen_znn的博客 8407

【Android】利用WindowsManager悬浮窗播放本地视频以及下载线上视频保存在本地

基于目前又重新拾起了分屏的项目需求,对之前研究的分屏播放视频做了更深入的研究。在之前的基础上做了改进和用户优化上的处理,实现了原生的VideoView加载本地视频。并使用FileDownLoader下载大文件的库来将线上视频文件下载到本地。 1.必要的权限 &lt;uses-permission android:name="android.permission.INTERN...

张迅之的博客 4192

绕过Cloudflare的两种简便方案

绕过Cloudflare的两种简便方案

自成背后的博客 1万+

Android(四十五):Service - StartService、StopService实现媒体播放

实现媒体播放(与直接播放媒体资源的对比) 目录结构 源码 布局 Resources/layout/main.xml<?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_p

You瞧谁不起 - 道不尽世间的沧桑,诉不完人生的悲凉 1661

详解大端模式和小端模式

详解大端模式和小端模式 一、大端模式和小端模式的起源         关于大端小端名词的由来,有一个有趣的故事,来自于Jonathan Swift的《格利佛游记》:Lilliput和Blefuscu这两个强国在过去的36个月中一直在苦战。战争的原因:大家都知道,吃鸡蛋的时候,原始的方法是打破鸡蛋较大的一端,可以那时的皇帝的祖父由于小时侯吃鸡蛋,按这种方法把手指弄破了,因此他的父亲,就下令,命令

ce123的技术博客 19万+

路径规划 | 图解Informed RRT*算法(附ROS C++/Python/Matlab仿真)

Informed RRT*算法针对RRT*算法进行了采样优化,用椭圆采样代替全局均匀采样,避免了RRT*算法搜索树上产生过多冗余分支的缺陷。本文图解Informed RRT*原理,并提供ROS C++/Python/Matlab三种实现加深理解

FRIGIDWINTER的博客 7484

android视频聊天桌面小窗口怎么实现,android视频通话悬浮窗的适配

前序按项目交互要求,需要把视频通话界面,缩小至悬浮窗显示,基本实现思路这个比较好想,就是启用一个service,在里面用WindowManager去addView来展示悬浮窗画面。基本效果是有了,但填坑之路才刚开始。。坑一:WindowManager.LayoutParam.type的选取选择TYPE_TOAST,如果期间有toast弹出,在android7.1.1会崩溃if (Build.VER...

weixin_35748595的博客 2039

Python 爬虫实战:爬取评论数据做情感分析

摘要:本文介绍基于Python的京东商品评论爬取与情感分析全流程实现。通过Requests库抓取评论数据接口,结合JSON解析获取结构化评论信息。利用SnowNLP进行中文文本情感分析,量化用户评价的情感倾向(正面/负面/中性)。结果显示正面评论占比66.3%,负面评论13.3%,关键词分析发现"卡顿""发热"是主要负面因素。该方法可应用于产品优化、品牌管理等场景,为决策提供数据支持。

2503_91057718的博客 1709

android 微信浮窗实现_转载:Android悬浮窗的实现

0. 前言现在很多应用都使用到悬浮窗,例如微信在视频的时候,点击Home键,视频小窗口仍然会在屏幕上显示。这个功能在很多情况下都非常有用。那么今天我们就来实现一下Android悬浮窗,以及探索一下实现悬浮窗时的易错点。1. 实现原理1.1 悬浮窗插入接口在实现悬浮窗之前,我们需要知道通过什么接口,能够将一个控件放入到屏幕中去。Android的界面绘制,都是通过WindowMananger的服务来实...

weixin_42315701的博客 1337

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Android悬浮窗播放视频

大家应该很喜欢这样的场景:一边打游戏一边看视频,生活娱乐两不误。这样应该怎么去实现呢?Android有提供悬浮窗API,使用悬浮窗播放视频,可以悬浮在其他应用上。有人可能会说,悬浮窗是不是会遮挡界面,导致用户体验不够好。总是有办法解决的,我们可以设计一个灵活的悬浮窗,窗口可以随时调整大小、任意拖动位置,这样就完美了。让我们看看小窗口播放效果。 首先,需要在Manifest.xml里申请权限:...

徐福记456 3万+

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

android多悬浮窗口播放器,Android实现悬浮播放器

1. 实现的大概流程:首先一个本地的视频正在播放时(MovieActivity类),程序里用变量保存当前播放视频的URI和MIME类型,当点击某个按钮时,会先把当前视频的播放位置保存到数据库里,然后开始进入悬浮框初始化(显示位置、大小、属性等),悬浮框里包含了VideoView类,这个类就是用于播放视频,将之前保存的数据(URI等)对其赋值,然后关闭当前播放视频的窗口,这样浮动视频框就出来了!同样...

weixin_39717121的博客 2152

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

实现小窗口播放视频ijkplayer

1:配置 android { compileSdkVersion 29 buildToolsVersion “29.0.2” defaultConfig { applicationId “com.example.mydemo01” minSdkVersion 15 targetSdkVersion 29 versionCode 1 versionName “1.0” testInstrumenta...

wzy_1704A的博客 1304

android浮窗播放器,Android仿优酷视频的悬浮窗播放效果

之前接了需求要让视频播放时可以像优酷视频那样在悬浮窗里播放,并且悬浮窗和主播放页面之间要实现无缝切换,项目中使用的是自封装的ijkplayer这个要求就代表不能在悬浮窗中新建视频控件,所以需要在悬浮窗中复用主页面的视频控件,以达到无缝衔接的效果。主页面对应的视频控件的父viewandroid:id="@+id/vw_live"android:layout_width="match_parent"a...

weixin_42330839的博客 732

Android: Service中创建窗口Dialog

Android: Service中创建窗口显示(TYPE_SYSTEM_ALERT, TYPE_SYSTEM_OVERLAY) 有时候需要在显示UI的时候不中断原来的Activity 比如在播放视频时或者玩游戏时,需要显示某个菜单(可以是系统提示,或类似于TV菜单) 显然用Activity来做是不行的,因为新Activity启动的时候会把原来的Activity pause

super_spy的专栏 1099

android service 创建窗口,Android Service中创建窗口显示

有时候需要在显示UI的时候不中断原来的Activity比如在播放视频时或者玩游戏时,需要显示某个菜单(可以是系统提示,或类似于TV菜单)显然用Activity来做是不行的,因为新Activity启动的时候会把原来的Activity pause掉怎么做呢,可以参考系统电量提示窗口或statusbar那样在service中启动窗口新窗口将会出现在UI最上层,但不会中断原来的Activity效果图,一个...

weixin_39562185的博客 294

android service 创建窗口,Android: Service中创建窗口显示(TYPE

有时候需要在显示UI的时候不中断原来的Activity比如在播放视频时或者玩游戏时,需要显示某个菜单(可以是系统提示,或类似于TV菜单)显然用Activity来做是不行的,因为新Activity启动的时候会把原来的Activity pause掉怎么做呢,可以参考系统电量提示窗口或statusbar那样在service中启动窗口新窗口将会出现在UI最上层,但不会中断原来的Activity效果图,一个...

weixin_35123329的博客 487

ExoPlayer视频悬浮窗实现:全局可拖动的小窗口播放

你是否曾在使用视频应用时遇到这样的困扰:想要一边观看教程视频一边操作其他应用,却不得不反复切换窗口?或者在通勤途中希望视频始终保持在屏幕一角,不影响聊天回复?ExoPlayer作为Android平台最强大的媒体播放引擎,提供了实现全局悬浮播放的完整能力。本文将详解如何构建可拖动、生命周期可控的悬浮窗播放组件,让你的应用具备媲美主流视频平台的多任务播放体验。 读完本文你将掌握: - 悬浮窗权限动态...

gitblog_00517的博客 580

Android可拖动缩放视频悬浮窗

直接上图 可进行三级缩放和拖动的视频悬浮窗口 一、悬浮窗口 1.1、创建WindowManager //创建params,控制大小位置 mParams = WindowManager.LayoutParams() //悬浮窗口 mWindowManager = application.getSystem...

weixin_30783629的博客 2460

Android: Service中创建悬浮窗口显示

有时候需要在显示UI的时候不中断原来的Activity 比如在播放视频时或者玩游戏时,需要显示某个菜单(可以是系统提示,或类似于TV菜单) 显然用Activity来做是不行的,因为新Activity启动的时候会把原来的Activity pause掉 怎么做呢,可以参考系统电量提示窗口或statusbar那样在service中启动窗口 新窗口将会出现在UI最上层,但不会中断原来的Activi...

蚁人日记 1427

android悬浮窗口播放动画,Android视频悬浮窗

这个悬浮窗是一个类似于微信通话的小屏视频框,利于Service开启和保持。悬浮是利用WindowManager实现创建FloatingWindowService服务类public class FloatingWindowService extends Service implements View.OnClickListener {private WindowManager windowManag...

weixin_39947351的博客 743
上一篇: Service: 二、简单的音乐播放器
下一篇: WorkManager笔记: 一、基础入门
孟老板007
博客等级 码龄5年 19粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值