android 悬浮窗

现在很多应用都使用到悬浮窗,例如微信在视频的时候,点击Home键,视频小窗口仍然会在屏幕上显示。这个功能在很多情况下都非常有用。

1、申请权限


    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
    <uses-permission android:name="android.permission.GET_TASKS" />
class MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_layout)

        startFloatingService()

    }
    @RequiresApi(api = Build.VERSION_CODES.M)
    fun startFloatingService() {
        if (!Settings.canDrawOverlays(this)) {
            startActivityForResult(
                Intent(
                    Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse(
                        "package:$packageName"
                    )
                ), 0x0002
            )
        } else {
            try {
                startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
            } catch (e: Exception) {
                Log.i(TAG, "start ACTION_ACCESSIBILITY_SETTINGS fail: " + e.message)  
                startActivity(Intent(Settings.ACTION_SETTINGS))
            }
        }
    }

    // 显示悬浮窗
    fun Show(view: View?) {
        FloatingClickService.showFloat(this)

    }

    // 隐藏悬浮窗
    fun Hide(view: View?) {
        FloatingClickService.hideFloat()
    }



}

2、创建悬浮窗服务

class FloatingClickService : Service() {
     
    private var manager: WindowManager? = null
    private var mFloatLayout: LinearLayout? = null
    private var settings: ImageView? = null  
    private var tip: TextView? = null
    private var params: WindowManager.LayoutParams? = null
    private var animation: AnimationF? = null

    private val inflater by lazy { LayoutInflater.from(application) }


    override fun onCreate() {
        super.onCreate()
        mInstance = this
        setFloatView()
    }

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

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        //适配android8以上
        val builder = Notification.Builder(this.getApplicationContext()); //获取一个Notification构造器
       
        val nfIntent = Intent(this, MainActivity::class.java)
        builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent    
           builder.setContentText("后台运行")
        startForeground(110, builder.build())
        return super.onStartCommand(intent, flags, startId)
    }

    /**
     * 移除悬浮窗,停止服务
     */
    fun hide() {
        mInstance = null
        manager!!.removeView(mFloatLayout) // 移除悬浮窗
        if (mapView.size > 0 && mapViewPos > 0) {
            mapView.forEach { t, u ->
                manager?.removeView(u)
                mapViewPos--
            }
        }
        this.stopSelf() // 停止服务
        onDestroy()
    }     

    private fun setFloatView() {
        // 从布局文件,生成悬浮窗
        mFloatLayout = inflater.inflate(R.layout.float_view, null) as LinearLayout      
        // 添加悬浮窗至系统服务
        params = getParams()
        manager = application.getSystemService(WINDOW_SERVICE) as WindowManager
        manager!!.addView(mFloatLayout, params)
         // 浮动窗口按钮
        settings = mFloatLayout!!.findViewById<View>(R.id.setting) as ImageView
        mFloatLayout!!.measure(
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
        )        settings!!.setOnTouchListener(touchListener) //
        settings!!.setOnClickListener(clickListener) // 添加setting按钮响应逻辑,其他按钮可以类似添加
        tip = mFloatLayout!!.findViewById<View>(R.id.tip) as TextView        // 为按钮添加动画效果
        val ids = intArrayOf(R.id.setting, R.id.search, R.id.note, R.id.link, R.id.alarm)
        animation = AnimationF(mFloatLayout!!, ids)
}
    // 拖动浮标时修改浮标位置
    var touchListener = OnTouchListener { v, event ->
        params!!.x = event.rawX.toInt() - settings!!.measuredWidth / 2
        params!!.y = event.rawY.toInt() - settings!!.measuredHeight / 2

        manager!!.updateViewLayout(mFloatLayout, params)
        false // 此处必须返回false,否则OnClickListener获取不到监听
    }
 var clickListener = View.OnClickListener { v ->
        if (v === settings) {
            animation!!.Setting(null) // 切换悬浮窗显示效果
        }
}
    private fun getParams(): WindowManager.LayoutParams {
        val wmParams = WindowManager.LayoutParams()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            wmParams.type = WindowManager.LayoutParams.TYPE_PHONE
        } // 设置window type
        wmParams.format = PixelFormat.RGBA_8888 // 设置图片格式,效果为背景透明
        wmParams.flags =
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // 设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
        wmParams.gravity = Gravity.LEFT or Gravity.TOP // 调整悬浮窗显示的停靠位置为左侧置顶
        // 以屏幕左上角为原点,设置x、y初始值(10,10),相对于gravity
        wmParams.x = 10
        wmParams.y = 10
        // 设置悬浮窗口长宽数据
        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT
        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT
        return wmParams
    }

    companion object {
        /**
         * 显示悬浮窗
         */
        fun showFloat(context: Context) {
            if (mInstance == null) {
                val intent = Intent(context, FloatingClickService::class.java)
                intent.putExtra("inputExtra", "startService")
                ContextCompat.startForegroundService(context, intent)

            }
        }

        /**
         * 关闭悬浮窗
         */
        fun hideFloat() {
            if (mInstance != null) {
                mInstance!!.hide()
            }

        }

        private var mInstance: FloatingClickService? = null
    }
)
           



WindowManager的flag

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夢鑰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值