南京做公司网站的公司哪家好,怎么做点播网站,招商网址,亚马逊网站建设的意义目录
1 前言
1.1 准备知识
1.2 问题概述
2 解决方案
3 代码部分
3.1 动态更新窗口焦点
3.2 窗口监听返回事件
3.3 判断焦点是否在窗口内部
3.4 窗口监听焦点移入/移出 1 前言
1.1 准备知识
1#xff09;开发环境#xff1a;
2D开发环境#xff1a;所有界面或弹窗…目录
1 前言
1.1 准备知识
1.2 问题概述
2 解决方案
3 代码部分
3.1 动态更新窗口焦点
3.2 窗口监听返回事件
3.3 判断焦点是否在窗口内部
3.4 窗口监听焦点移入/移出 1 前言
1.1 准备知识
1开发环境
2D开发环境所有界面或弹窗都在主界面显示3D开发环境保留原生Android的主界面在主界面之外绘制各种窗口配合3D渲染以实现3D效果。
2焦点就是Hover点、中央注视点、可与用户交互的点。
3窗口就是系统弹窗内部有addView本文窗口监听即View监听。
4事件分发正常Android设备使用如下3种本文采用的第3种setOnHoverListener获取事件。
setOnTouchListener(MotionEvent::InputEvent)手机、平板、车载等屏幕可触控的2D设备setOnKeyListener(KeyEvent::InputEvent)电视、投影仪等屏幕不可触控的2D设备setOnHoverListener(MotionEvent::InputEvent)AR眼镜等增强现实设备。
5Hover事件分发当前View在焦点移出不再是Hover状态时不会立即发送ACTION_HOVER_EXIT退出事件需要等到下一个View获取到ACTION_HOVER_ENTER状态时才会发送上一个View的ACTION_HOVER_EXIT退出事件。
6窗口内部View的Hover事件转化过程
RootView会先获取到ACTION_HOVER_ENTER事件当进入ChildView时ChildView会先获取到ACTION_HOVER_ENTER事件然后RootView会获取到ACTION_HOVER_EXIT事件当从ChildView退出时ChildView会先获取到ACTION_HOVER_EXIT事件然后RootView会获取到ACTION_HOVER_ENTER事件。
1.2 问题概述 问题描述在Android悬浮弹窗上双击返回主界面响应返回事件。 问题原因悬浮弹窗设置了flag为窗口不可获取焦点即WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE。 问题分析
悬浮弹窗设置flag为窗口不可获取焦点是为了不影响主界面的焦点响应Android默认主界面的窗口是获取焦点的如果悬浮弹窗设置flag可获取焦点那么Android的事件分发是无法发送到主界面的会将事件分发给当前可获取焦点的悬浮窗口如下图左侧图1为悬浮窗口右侧图2为主界面某应用打开一个Activity。图1悬浮窗口是常驻于图2主界面的左侧且默认不可获取焦点但在特请情况时可获取焦点如展开键盘、焦点在此悬浮窗口内部。 解决方案当焦点在悬浮窗口内部时设置窗口flag可获取焦点当焦点不在悬浮窗口内部时设置窗口flag不可获取焦点。 2 解决方案 方案主要分为如下几步
窗口默认不可获取焦点窗口监听焦点的移入/移出事件窗口监听到焦点移入判断窗口是否可获取焦点否——设置窗口可获取焦点是——不做任何操作窗口监听到焦点移出判断焦点是否在窗口内部否——设置窗口不可获取焦点是——不做任何操作 读者可思考如下2个问题
1问题1为什么在窗口监听到焦点移入后要再判断窗口是否可获取焦点
2问题2为什么在窗口监听到焦点移出后要再判断焦点是否在窗口内部 相信本文《1.1 准备知识的第6部分》可以给你一些灵感。 3 代码部分
3.1 动态更新窗口焦点 核心API
WindowManager.updateViewLayoutWindowManager.LayoutParams.flags WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE private fun updateNotificationParams(focusable: Boolean) {initLayoutParams(focusable)mUiHandler.post {synchronized(this) {if (mIsBarWindowAdded) {try {mWindowManager.updateViewLayout(mNotificationBar, mLayoutParams)} catch (e: Exception) {e.printStackTrace()}}}}}private fun initLayoutParams(focusable: Boolean) {mLayoutParams WindowManager.LayoutParams().apply {type WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAYval density mContext.resources.displayMetrics.densitywidth (640 * density).toInt()height (640 * density).toInt()flags 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 or WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITSif (!focusable) {flags flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE}format PixelFormat.RGBA_8888 // 去除默认时有的黑色背景设置为全透明gravity Gravity.TOP or Gravity.STARTtitle MB_SYSUI_NOTIFICATIONx (680 * density).toInt() // adb shell wm size 1920x1280y 0setTranslationZ(TRANSLATION_Z_200CM)setRotationYAroundOrigin(22.0f)}}
3.2 窗口监听返回事件 在自定义View中重写dispatchKeyEvent方法监听keyCode KeyEvent.KEYCODE_BACK事件即可。 override fun dispatchKeyEvent(event: KeyEvent): Boolean {if (event.keyCode KeyEvent.KEYCODE_BACK) {Log.i(TAG, dispatchKeyEvent: KEYCODE_BACK)LiveDataBus.get().with(Constants.NOTIFICATION_EVENT_BUS_CLOSE_FOLD_PAGE).value true}return super.dispatchKeyEvent(event)}
3.3 判断焦点是否在窗口内部 mRootView.post {val locationXY IntArray(2)mRootView.getLocationOnScreen(locationXY)val locationX locationXY[0]val locationY locationXY[1]val measuredWidth mRootView.measuredWidthval measuredHeight mRootView.measuredHeight}/*** 焦点就是Hover点、中央注视点、可与用户交互的点。** if (rawX locationX || rawX locationX measuredWidth || rawY locationY || rawY locationY measuredHeight) {* // 焦点不在View内部* Log.i(TAG, isViewNotFocus: 焦点不在View内部)* } else {* // 焦点在View内部* Log.i(TAG, isViewNotFocus: 焦点在View内部)* }** param locationX View相对于屏幕位置X* param locationY View相对于屏幕位置Y* param measuredWidth View宽* param measuredHeight View高* param rawX 焦点相对于屏幕位置X* param rawY 焦点相对于屏幕位置Y** return 焦点是否未在View内部*/private fun isViewNotFocus(locationX: Int,locationY: Int,measuredWidth: Int,measuredHeight: Int,rawX: Float,rawY: Float): Boolean {val density context.resources.displayMetrics.densityreturn rawX locationX 50 * density || rawX locationX measuredWidth - 100 * density || rawY locationY 15 * density || rawY locationY measuredHeight - 60 * density}
3.4 窗口监听焦点移入/移出
// 注Focus移出时需要包含边界。mRootView.setOnHoverListener { v, event -when (event.action) {MotionEvent.ACTION_HOVER_ENTER - {Log.i(TAG,OnHoverListener: 进入, action ${event.action},motionX ${event.rawX},motionY ${event.rawY})LiveDataBus.get().with(NOTIFICATION_EVENT_BUS_FOCUSABLE).value?.let {if (!(it as Boolean)) {Log.i(TAG, OnHoverListener: 进入, focus-true-0000)LiveDataBus.get().with(NOTIFICATION_EVENT_BUS_FOCUSABLE).value true}} ?: let {Log.i(TAG, OnHoverListener: 进入, focus-true-1111)LiveDataBus.get().with(NOTIFICATION_EVENT_BUS_FOCUSABLE).value true}}MotionEvent.ACTION_HOVER_MOVE - {}MotionEvent.ACTION_HOVER_EXIT - {Log.i(TAG,OnHoverListener: 退出, action ${event.action},motionX ${event.rawX},motionY ${event.rawY})if (isViewNotFocus(locationX,locationY,measuredWidth,measuredHeight,event.rawX,event.rawY)) {Log.i(TAG, OnHoverListener: 退出, focus-false)LiveDataBus.get().with(NOTIFICATION_EVENT_BUS_FOCUSABLE).value false}}}false}