欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿腾讯视频实现悬浮窗效果

程序员文章站 2022-06-16 10:53:59
前言相信大家对android悬浮窗应该是很熟悉了,比如说腾讯视频、爱奇艺等app都有悬浮窗功能。在你打游戏的同时还可以看视频,充分利用屏幕空间。还有微信,360手机卫士等app也有悬浮窗功能。那么an...

前言

相信大家对android悬浮窗应该是很熟悉了,比如说腾讯视频、爱奇艺等app都有悬浮窗功能。在你打游戏的同时还可以看视频,充分利用屏幕空间。还有微信,360手机卫士等app也有悬浮窗功能。那么android悬浮窗是怎么实现的呢?

项目源码:android仿腾讯视频悬浮窗的实现

其实并不难,核心代码就只有一行:

windowmanager.addview(view, layoutparams)

效果图

Android仿腾讯视频实现悬浮窗效果

 对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>

对应的界面: 

Android仿腾讯视频实现悬浮窗效果

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悬浮窗的资料请关注其它相关文章!

相关标签: android 悬浮窗