热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android如何监听屏幕旋转

这篇文章主要介绍了如何监听Android屏幕旋转,帮助大家更好的理解和学习使用Android开发,感兴趣的朋友可以了解下

背景

关于个人,前段时间由于业务太忙,所以一直没有来得及思考并且沉淀点东西;同时组内一个个都在业务上能有自己的思考和总结,在这样的氛围下,不由自主的驱使周末开始写点东西,希望自己除了日常忙于业务,可以沉淀点东西,加上自己的成长..

关于切入点,最近在做应⽤内悬浮球功能时,需要监听屏幕旋转事件来对悬浮球的位置进⾏调整,发现有些情况下并不能收到系统回调,思考了⼀翻,做了⼀个屏幕旋转的模拟监听,基本上能达到⽬的。

问题

悬浮球在停⽌拖拽后,需要贴边到⼿机屏幕的左右两侧。

在竖屏状态下,x坐标为0即为左边缘,x坐 标为屏幕宽度即为右边缘。

但是在横屏状态下,情况就⽐较复杂了。现在⼤部分Android⼿机都是刘 海屏的设计,在全屏状态下,悬浮球贴边时不能收到刘海下⾯去,不然就点不到了。

所以此时需要算 出刘海的宽度,以此宽度作为悬浮球左边的起始位置,这样悬浮球贴边的时候就不会躲到刘海下⾯ 去。 如下图所示

但是在屏幕旋转之后,刘海到了右边,左边就不应该以刘海的宽度作为悬浮球的起点了。 这样的话就需要监听屏幕的旋转了,配合屏幕⽅向的⻆度,就能正确判断。监听屏幕的旋转只需要重 写Activity的onConfiguratuonChanged⽣命周期。

override fun onConfigurationChanged(newConfig: Configuration) {
 super.onConfigurationChanged(newConfig)
 Log.i(TAG, "on configuration changed")
}

在AndroidManifest中配置

android:cOnfigChanges="orientation|screenSize"

此时发现了⼀个问题,当把Activity的screenOrientation设置成sensorLandscape时,即使屏幕旋转 也收不到这个回调(这个和之前的理解有点不⼀样)。于是将screenOrientation设置成sensor,屏 幕旋转就能正常回调到这⾥,多试⼏次发现,只有在横屏和竖屏之间切换时才能收到回调,如果直接 将横屏倒过来,就是横屏状态不变,⽅向调转,此时也不会收到回调。

解决思路

既然onConfigurationChanged收不到回调,还有另外⼀个办法,就是监听屏幕⽅向度数,代码如下

mOrientatiOnEventListener= object : OrientationEventListener(this) {
 override fun onOrientationChanged(orientation: Int) {
 Log.i(TAG, "on orientation changed angle is $orientation")
 if (orientation > 340 || orientation <20) {
 //0
 } else if (orientation in 71..109) {
 //90
 } else if (orientation in 161..199) {
 //180
 } else if (orientation in 251..289) {
 //270
 }
 }
}

通过度数来判断刘海是在左边还是在右边,即270度时在左边,90度时在右边。这种&#12101;式看起来可以 解决问题,但是多旋转&#12047;次就发现&#12060;有其他问题。按照正常思维,屏幕的显示&#12101;向应该和这个度数&#12032; 致才对,即屏幕的显示应该是&#12163;上&#12157;下的。但是下图就不是这样。

此时度数为90,屏幕却倒&#12148;着显示的,并没有旋转成正&#12148;状态,但是按照上&#12207;的代码,会将90度判定 为正常90度正&#12148;显示的状态,此时去修改悬浮球的位置就是错误的。

那如果在收到onOrientationChanged这个回调时能判断&#12032;下屏幕显示的&#12101;向呢,就是在度数达到90 度范围时,同时判断屏幕的显示&#12101;向,即两个条件同时满&#12188;才判定成屏幕旋转了。

&#12132;下&#12207;的代码判定屏幕显示&#12101;向

val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as
WindowManager
val rotation = windowManager.defaultDisplay&#63;.rotation
//rotation为常量0、1、2、3,分别表示屏幕的四个&#12101;向

通过这样的判断基本上能将屏幕旋转事件监听准确了,onOrientationChanged这个回调很灵敏,&#12095; 机屏幕稍微动&#12032;下就会回调。那我希望模拟正常的屏幕旋转事件来修改悬浮球的位置,总不能很频繁 的刷新吧。这&#12197;做&#12032;下控制就好,全部代码如下:

object ScreenOrientationHelper {
 val ORIENTATION_TYPE_0 = 0
 val ORIENTATION_TYPE_90 = 90
 val ORIENTATION_TYPE_180 = 180
 val ORIENTATION_TYPE_270 = 270
 private var mOrientationEventListener: OrientationEventListener&#63; = null
 private var mScreenOrientationChangeListener:
   ScreenOrientationChangeListener&#63; = null
 private var currentType = ORIENTATION_TYPE_0

 fun init(context: Context, listener: ScreenOrientationChangeListener) {
  mScreenOrientatiOnChangeListener= listener
  mOrientatiOnEventListener= object :
    OrientationEventListener(context) {
   override fun onOrientationChanged(orientation: Int) {
    if (mScreenOrientatiOnChangeListener== null) {
     return
    }
    if (orientation > 340 || orientation <20) {
     //0
     if (currentType == 0) {
      return
     }
     if (getScreenRotation(context) == Surface.ROTATION_0) {
      mScreenOrientationChangeListener!!.onChange(ORIENTATION_TYPE_0)
      currentType = ORIENTATION_TYPE_0
     }
    } else if (orientation in 71..109) {
     //90
     if (currentType == 90) {
      return
     }
     val angle = getScreenRotation(context)
     if (angle == Surface.ROTATION_270) {
      mScreenOrientationChangeListener!!.onChange(ORIENTATION_TYPE_90)
      currentType = ORIENTATION_TYPE_90
     }
    } else if (orientation in 161..199) {
     //180
     if (currentType == 180) {
      return
     }
     val angle = getScreenRotation(context)
     if (angle == Surface.ROTATION_180) {
      mScreenOrientationChangeListener!!.onChange(ORIENTATION_TYPE_180)
      currentType = ORIENTATION_TYPE_180
     }
    } else if (orientation in 251..289) {
     //270
     if (currentType == 270) {
      return
     }
     val angle = getScreenRotation(context)
     if (angle == Surface.ROTATION_90) {
      mScreenOrientationChangeListener!!.onChange(ORIENTATION_TYPE_270)
      currentType = ORIENTATION_TYPE_270
     }
    }
   }
  }
  register()
 }

 private fun getScreenRotation(context: Context): Int {
  val windowManager =
    context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
  return windowManager.defaultDisplay&#63;.rotation &#63;: 0
 }

 fun register() {
  if (mOrientationEventListener != null) {
   mOrientationEventListener!!.enable()
  }
 }

 fun unRegister() {
  if (mOrientationEventListener != null) {
   mOrientationEventListener!!.disable()
  }
 }

 interface ScreenOrientationChangeListener {
  /**
   *
   * @param orientation
   */
  fun onChange(orientation: Int)
 }
}

使&#12132;的话,直接这样:

ScreenOrientationHelper.init(this, object :
ScreenOrientationHelper.ScreenOrientationChangeListener {
 override fun onChange(orientation: Int) {
  when(orientation) {
   ScreenOrientationHelper.ORIENTATION_TYPE_0 -> {}
   ScreenOrientationHelper.ORIENTATION_TYPE_90 -> {}
   ScreenOrientationHelper.ORIENTATION_TYPE_180 -> {}
   ScreenOrientationHelper.ORIENTATION_TYPE_270 -> {}
  }
 }
})

通过上&#12207;的代码发现,在onOrientationChanged回调90度范围内时,判定屏幕显示&#12101;向是和 Surface.ROTATION_270&#12112;较的,&#12157;270范围内时是和Surface.ROTATION_90&#12112;较的。看得出来&#11974;度 是顺时针递增的,&#12157;屏幕&#12101;向是逆时针计算度数的。

其他问题

在测试过程中,上&#12207;的&#12101;案还存在另外&#12032;个问题,虽然onOrientationChanged这个回调很灵敏,但 是也有度数不变&#12157;屏幕&#12101;向旋转的情况发&#12131;,即保持屏幕&#12101;向不变,&#12157;是增加屏幕的坡度(将&#12095;机&#12032; 边贴在桌&#12207;,慢慢&#12148;起来),在坡度达到&#12032;定时,屏幕会发&#12131;旋转,此时onOrientationChanged是 不会回调的,因为没有变化。这样就收不到屏幕旋转的回调了,但是在实际&#12132;&#12095;机的场景中,这种情 况是&#12112;较少的,可以亲身试试看。

小结

在平时开发中,要区分是哪种状态横屏的场景&#12112;较少,否则我认为Android会给出准确的回调的。 Android设备碎&#12122;化严重,除了刘海,在屏幕的下边缘还有虚拟导航栏,在不同的系统设置下,这个 导航栏不显示状态会不&#12032;样。那么这时候在悬浮球贴边这个需求中就不仅仅要考虑刘海了,还得考虑 导航栏。更有甚者,在旋转过程中,虚拟导航栏会&#12032;直保持在&#12032;个&#12101;向,和刘海叠加。那么要清楚的 算位置,第&#12032;步就是要监听屏幕的旋转了。

以上就是如何监听Android屏幕旋转的详细内容,更多关于监听Android屏幕旋转的资料请关注其它相关文章!


推荐阅读
  • 本文旨在提供一套高效的面试方法,帮助企业在短时间内找到合适的产品经理。虽然观点较为直接,但其方法已被实践证明有效,尤其适用于初创公司和新项目的需求。 ... [详细]
  • 本文介绍了如何通过设置背景形状来轻松地为 Android 的 TextView 添加圆形边框。我们将详细讲解 XML 代码的配置,包括圆角、描边和填充等属性。 ... [详细]
  • 在使用STM32Cube进行定时器配置时,有时会遇到延时不准的问题。本文探讨了可能导致延时不准确的原因,并提供了解决方法和预防措施。 ... [详细]
  • Netflix利用Druid实现高效实时数据分析
    本文探讨了全球领先的在线娱乐公司Netflix如何通过采用Apache Druid,实现了高效的数据采集、处理和实时分析,从而显著提升了用户体验和业务决策的准确性。文章详细介绍了Netflix在系统架构、数据摄取、管理和查询方面的实践,并展示了Druid在大规模数据处理中的卓越性能。 ... [详细]
  • 深入理解Lucene搜索机制
    本文旨在帮助读者全面掌握Lucene搜索的编写步骤、核心API及其应用。通过详细解析Lucene的基本查询和查询解析器的使用方法,结合架构图和代码示例,带领读者深入了解Lucene搜索的工作流程。 ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • DeepMind迁入谷歌伦敦新总部:人工智能研究的新里程碑
    谷歌旗下的人工智能研究机构DeepMind已正式入驻位于伦敦国王十字车站潘克拉斯广场6号的新总部。这座现代化的办公大楼不仅为DeepMind提供了宽敞的研究空间,也象征着谷歌对AI技术发展的高度重视。 ... [详细]
  • 在项目部署后,Node.js 进程可能会遇到不可预见的错误并崩溃。为了及时通知开发人员进行问题排查,我们可以利用 nodemailer 插件来发送邮件提醒。本文将详细介绍如何配置和使用 nodemailer 实现这一功能。 ... [详细]
  • 本文将探讨Java编程语言中对象和类的核心概念,帮助读者更好地理解和应用面向对象编程的思想。通过实际例子和代码演示,我们将揭示如何在Java中定义、创建和使用对象。 ... [详细]
  • 本文详细探讨了JavaScript中的作用域链和闭包机制,解释了它们的工作原理及其在实际编程中的应用。通过具体的代码示例,帮助读者更好地理解和掌握这些概念。 ... [详细]
  • 本文详细介绍了如何在 Android 开发中高效地管理和使用资源,包括本地资源和系统资源的访问方法。通过实例和代码片段,帮助开发者更好地理解和应用资源管理的最佳实践。 ... [详细]
  • Python 内存管理机制详解
    本文深入探讨了Python的内存管理机制,涵盖了垃圾回收、引用计数和内存池机制。通过具体示例和专业解释,帮助读者理解Python如何高效地管理和释放内存资源。 ... [详细]
  • C#设计模式学习笔记:观察者模式解析
    本文将探讨观察者模式的基本概念、应用场景及其在C#中的实现方法。通过借鉴《Head First Design Patterns》和维基百科等资源,详细介绍该模式的工作原理,并提供具体代码示例。 ... [详细]
  • 本文详细介绍了划分树这一数据结构,重点探讨了其在子树和中值计算中的应用及优化方法。 ... [详细]
  • Android Studio 安装与配置指南
    本教程详细介绍了如何下载并安装 Android Studio,包括设置 SDK 路径和优化启动性能的方法。通过这些步骤,您可以顺利地开始开发 Android 应用。 ... [详细]
author-avatar
mobiledu2502921033
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有