Android仿腾讯视频实现悬浮窗效果
前言
相信大家对android悬浮窗应该是很熟悉了,比如说腾讯视频、爱奇艺等app都有悬浮窗功能。在你打游戏的同时还可以看视频,充分利用屏幕空间。还有微信,360手机卫士等app也有悬浮窗功能。那么android悬浮窗是怎么实现的呢?
项目源码:android仿腾讯视频悬浮窗的实现
其实并不难,核心代码就只有一行:
windowmanager.addview(view, layoutparams)
效果图
对view比较熟悉的同学们应该发现了,其实我们的悬浮窗就是一个view,我把只需要把view添加到windowmanager上就可以了。那么,开始讲细节了:
权限一定要记得加:
<uses-permission android:name="android.permission.system_alert_window" />
因为我们的悬浮窗要在launcher上或者在其他app上面运行,所以这里就用到了service,因为service可以默默地在后台运行。
实现大致步骤:
1.检查权限(如果没有权限跳转到授权界面)
2.在service中用inflate方法获取我们需要的view,设置位置参数等,加入到windowmanager里面
3.启动悬浮窗服务
view布局
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <imageview android:layout_width="200dp" android:layout_height="100dp" android:src="@drawable/huge"></imageview> <imageview android:id="@+id/close" android:src="@drawable/close" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginleft="170dp"> </imageview> </framelayout>
对应的界面:
floatingwindowservice
package com.example.floatingwindow import android.annotation.suppresslint import android.app.service import android.content.context import android.content.intent import android.os.build import android.os.ibinder import android.view.* import android.widget.imageview import android.widget.toast class floatingwindowservice : service(){ private lateinit var layoutparams: windowmanager.layoutparams private lateinit var windowmanager: windowmanager override fun onbind(intent: intent): ibinder? { // todo: return the communication channel to the service. throw unsupportedoperationexception("not yet implemented") } override fun onstartcommand(intent: intent, flags: int, startid: int): int { showfloatingwindow() return super.onstartcommand(intent, flags, startid) } @suppresslint("clickableviewaccessibility") private fun showfloatingwindow() { // 获取windowmanager服务 windowmanager = getsystemservice(context.window_service) as windowmanager // 新建悬浮窗控件 val view = layoutinflater.from(this).inflate(r.layout.window, null) // 设置layoutparam layoutparams = 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.gravity = gravity.left or gravity.top layoutparams.x = windowmanager.defaultdisplay.width layoutparams.y = 200 //设置flag layoutparams.flags = windowmanager.layoutparams.flag_not_focusable or windowmanager.layoutparams.flag_not_touch_modal or windowmanager.layoutparams.flag_layout_in_screen or windowmanager.layoutparams.flag_layout_inset_decor or windowmanager.layoutparams.flag_watch_outside_touch //设置view的宽高 layoutparams.width = windowmanager.layoutparams.wrap_content layoutparams.height = windowmanager.layoutparams.wrap_content //添加拖拽事件 view.setontouchlistener(floatingontouchlistener()) val close = view.findviewbyid<imageview>(r.id.close) close.setonclicklistener { stopself() windowmanager.removeview(view) toast.maketext(this,"close",toast.length_short).show() } // 将悬浮窗控件添加到windowmanager windowmanager.addview(view, layoutparams) } override fun ondestroy() { super.ondestroy() toast.maketext(this,"ondestroy",toast.length_short).show() } inner class floatingontouchlistener : view.ontouchlistener { private var x = 0f private var y = 0f @suppresslint("clickableviewaccessibility") override fun ontouch(v: view?, event: motionevent?): boolean { when(event?.action){ motionevent.action_down ->{ x = event.rawx y = event.rawy } motionevent.action_move ->{ val nowx = event.rawx val nowy = event.rawy val movedx = nowx - x val movedy = nowy - y x = nowx y = nowy layoutparams.x = (layoutparams.x + movedx).toint() layoutparams.y = (layoutparams.y + movedy).toint() windowmanager.updateviewlayout(v, layoutparams) } motionevent.action_up ->{ } } return false } } }
先获取windowmanager,加载我们的悬浮窗view,这里的type_application_overlay的作用是把我们的view设置成系统顶层窗口,显示在其他一切内容之上。type_system_overlay的作用也是一样的,只不过现在被遗弃调了。
设置初始位置:
初始位置,这里可以看一下android坐标系相关知识,android 零坐标在屏幕左上方。这里设置一下xy坐标的位置就可以。
设置flag:
设置flag的作用是让view不获取焦点。如果不做处理,view会遮住屏幕其他控件的点击事件。
拖拽功能:
floatingontouchlistener是一个内部类,它可以使用floatingwindowservice类中的变量。实现ontouchlistener接口,当屏幕点击时记录下当前位置,屏幕滑动时计算出划过的距离,修改layoutparams的xy坐标,调用windowmanager.updateviewlayout(v, layoutparams)方法就可以更新view当前位置。
mainactivity
package com.example.floatingwindow import android.content.intent import android.net.uri import android.os.build import android.os.bundle import android.provider.settings import android.widget.toast import androidx.appcompat.app.appcompatactivity class mainactivity : appcompatactivity() { override fun oncreate(savedinstancestate: bundle?) { super.oncreate(savedinstancestate) startfloatingservice() } private fun startfloatingservice() { if (build.version.sdk_int >= build.version_codes.m) { 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 (build.version.sdk_int >= build.version_codes.m) { if (!settings.candrawoverlays(this)) { toast.maketext(this, "授权失败", toast.length_short).show() } else { toast.maketext(this, "授权成功", toast.length_short).show() startservice(intent(this@mainactivity, floatingwindowservice::class.java)) } } } } }
到这里悬浮窗的实现基本就结束了。
码云项目源码:android仿腾讯视频悬浮窗的实现
以上就是android仿腾讯视频实现悬浮窗效果的详细内容,更多关于android悬浮窗的资料请关注其它相关文章!
上一篇: 一起来看看五条Python中的隐含特性