开发者社区> kylinarm> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Android 坐标总结

简介: 写这篇文章的原因是因为坐标遇到的坑太多了,所以要记录一下。 一.基本的坐标与获取 先来看看基本的一些内容。 假如一个屏幕的区域是这样,蓝色的那条叫状态栏(statusBar),下面橙色的那条叫导航(NavigationBar),中间绿色的是应用区域。
+关注继续查看

写这篇文章的原因是因为坐标遇到的坑太多了,所以要记录一下。

一.基本的坐标与获取

先来看看基本的一些内容。


img_3ca33c4f0226955b3fb19074a1227651.png

假如一个屏幕的区域是这样,蓝色的那条叫状态栏(statusBar),下面橙色的那条叫导航(NavigationBar),中间绿色的是应用区域。标题栏是应用区域里面的,因为现在很多都是用到自定义的标题栏而不是系统的标题栏,所以这里不介绍。

1.获取整个屏幕的宽高

整个屏幕的宽高指的是蓝色、绿色加起来的部分。(注意不算橙色部分)

WindowManager windowManager = getWindowManager();  
Display display = windowManager.getDefaultDisplay();  
screenWidth = display.getWidth();  
screenHeight = display.getHeight();  
2.获取状态栏高度

蓝色那栏状态栏

 public float getStatusBarHeight() {
        int height = 0;
        try {
            Resources resources = applicationContext.getResources();
            int resourceId = resources.getIdentifier("status_bar_height", "dimen","android");
            height = resources.getDimensionPixelSize(resourceId); 
        } catch (Exception e) {
            e.printStackTrace(); 
        }
        return height;
}
3.获取导航栏的高度
 private int getNavigationBarHeight() {
        int height = 0;
        try {
            Resources resources = applicationContext.getResources();
            int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
            height = resources.getDimensionPixelSize(resourceId);
        }catch (Exception e){
            e.printStackTrace();
        }
        return height;
}
4.获取应用区域宽高

这里先讲一个误区,有的人获取应用区域的高度,为了图方便用整体的高度(也就是1中的高度)减去状态栏的高度(也就是2中的高度)
这样做的话普通的手机是没问题的,但是对于前段时间新出的刘海屏手机,就会出问题,举个栗子,比如下面这款手机,我随便找张图

img_08152519981b83ed02fc13866e3b3cb2.png

它的状态栏是刘海的那一栏,也就是红框的上边。但是你用1中的方法获取到的并不会是整个屏幕的高度,而是红框中的区域,所以你用 小标题1获取的高度减去 小标题2的高度的话,肯定不准确的。
所以在获取高度这个操作上,最好不要使用运算操作,因为android机型很多,谁知道有什么机型会不会出问题。所以我们应该直接获取应用区域的宽高

Rect outRect = new Rect();
getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect);
int height = outRect.height()
int width= outRect.width()
5.测试高度

我们来测试下这4种方法获取到的高度,可以自己试试然后打印出来
我的手机是1920 x 1080 结果如下

img_082f38cfbe2344981f4171b72c599e21.png

(1)小标题1获取高度为1794
(2)小标题2获取高度为72
(3)小标题3获取高度为126
(4)小标题4获取高度为1722

可以看出 屏幕高度1794 + 底部导航栏高度126 = 1920
屏幕高度1794 - 状态栏高度72 = 应用区域高度 1722

二.获取高度时的坑

你以为能正常获取到这些高度就能正常使用?那还是太天真,这些东西的坑填都填不完,我也只能总结一些我碰到的,然而这肯定也仅仅是冰山一角。

1.状态栏的坑

这个就是我上面说的,普通手机获取整个屏幕的高度是正常的,但是在有刘海的手机上,获取的高度是不包括刘海部分的高度。
注意:这点我只是根据我用过的刘海机测试得出的,但是我不排除会有其它某些刘海机也会把刘海那部分的高度算进去。

2.底部导航栏的坑

在小标题4中的获取应用区域高度中,可以看出我计算得到内容区域的结果是1722,它是整个屏幕减去状态栏再减去导航栏得到的结果。
但是有些情况下,你会在没有显示导航栏的时候获取应用区域高度,比如旋转手机,如果在onConfigurationChanged方法中获取高度,对于某些手机,比如华为手机,会先计算outRect.height()再显示导航栏,这时outRect.height()的高度就是1722+126 而不是 1722 ,所以显示就会有问题。
对于这个问题,我的解决办法是在activity中outRect.height()方法只获取一次,因为activity是有生命周期的,第一次获取肯定会是在导航栏显示后获取,所以肯定是准确的,但这个解决方案的前提是一定会显示导航栏。

3.横屏情况下导航栏的坑

对于某些手机,当你切换至横屏的时候,它的导航栏会一直显示在右侧,比如我的华为机,而有些手机导航栏可能会在左侧也可能会在右侧,因为它一直固定在底部,比如小米的某些手机。那这种情况会出现什么问题呢,下面的内容我会涉及到,这里先把它引出来。

三.屏幕中各种坐标

这个问题其实很简单,你随便百度一下就能得到一张很可观的图,我这随便拿一张来说


img_4675f5cf5b9d0974eae2cd2b52a59211.png

这样看一眼就知道这些方法获取到的是哪段距离,然后我也只重点讲下期中一些坐标

1.getRawX与getRawY

这里我要说下这两个方法。这两个方法获取到的是距离屏幕边缘的距离,而不是应用区域的距离,如图


img_a6550a2624761a2b543ddd3c10244278.png
2.窗口WindowManager

如果你要自定义一个有宽高的窗口,你可以设置它的属性使用WindowManager.LayoutParams
而这个windowMangerlp可以设置两个参数windowMangerlp.x和windowMangerlp.y来表示这个窗口左上角的坐标。
注意,关键的地方来了,这个坐标的参考系不是整个屏幕,而是应用区域,也就是下图中红框的区域,而(0,0)则是我标出来的那个点。

img_64488ba8acf1fb6f83a00e1add5454e4.png

这里我就要补上上面说的第三个坑了,在做悬浮窗的时候,悬浮窗要随手指移动,动态设置悬浮窗的位置的方法是

windowMangerlp.x = event.getRawX() - event.getX()
windowMangerlp.y = event.getRawY() - event.getY()

那么问题来了,getRawX和windowMangerlp.x的坐标系并不是同一个坐标系,简单来说,在底部导航栏横屏时在左边的情况,你点我上图中画圈的那点,getRawX和getRawY以我的手机坐标不是(0,0)而是(126,72),那悬浮窗设置的坐标是(126,72),那显示的位置就不是画圈的那个地方了。
这里不光是这个问题,我只是举例栗子,我想引出的问题是要做坐标计算的操作,无论你处于什么状况,都必须要让这两个坐标的计算方法处于同一个坐标系中。可能说得不太好理解,拿我这个来说windowMangerlp.x和event.getRawX()进行了计算操作,但它们不处于同个坐标系,所以可能会出问题。

那我这里就想办法把这两个坐标放在同个坐标系中,要怎么做,无非两种方法,第一种把windowMangerlp.x 的坐标系扩展到getRawX的坐标系中,第二种方法是把getRawX的坐标系缩小到windowMangerlp.x 的坐标系中,我这里选择第二种方法。

其实我觉得这个变坐标系才是最难的操作,说白的就是把一个坐标系的(0,0)变成另一个坐标系的(0,0),这个不理解的话说明数学没学好
比如这里把event.getRawX()的0变成windowMangerlp.x的0,把event.getRawY()的0变成windowMangerlp.y的0,。看我的图第一眼的想法就是event.getRawX() - 导航栏高度,event.getRawY() - 状态栏高度。但是这样是不可行的,为什么,因为这两个高度是死的,就算我状态栏不显示或者我导航栏在右边等等,这样减的话肯定是错误的,那我们必须要动态获取画圈的地方距屏幕(0,0)的距离。
这里我想到了一个骚操作,其实这个距离,就是我内容区域view距屏幕的距离

 // 获取屏幕view
View decorView = ((Activity)mContext).getWindow().getDecorView();
view screenView = decorView.findViewById(android.R.id.content);

screenView 就是红框的区域

 int[] position = new int[2];
screenView.getLocationInWindow(position);
int paddingLeft = position[0];
int paddingTop = position[1];

然后修改坐标系

windowMangerlp.x  = event.getRawX() - event.getX() - position[0];
windowMangerlp.y= event.getRawY() - event.getY() - position[1];

用到坐标的地方坑比较多,只能碰到或怎样再补充,如果可以,建议App固定竖屏,因为很多问题其实都是横屏或者转屏引起的,一直设置为竖屏就没这么多逼事。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Android推送集成方案总结
刚做完推送集成方案,记录下坑。 这里记录的特性和使用时针对写blog时采用的sdk的,具体使用流程和限制还请参考官方给出的sdk. #### 1、推送规则 小米手机用小米推送; 华为手机用华为推送; 其他手机用友盟推送。
0 0
淘宝安卓端搜索架构升级总结
推荐语:这篇文章图文并茂地介绍了淘宝搜索滚动容器的技术演进过程,结合代码讲解页面结构划分、数据处理、交互效果,还包含了对逻辑抽象、功能拓展的思考,最后总结了可复用的架构。非常具有实践意义,推荐阅读学习! ——大淘宝技术终端开发工程师 门柳
0 0
Android | 老生常谈!屏幕适配原理 & 方案总结笔记
Android | 老生常谈!屏幕适配原理 & 方案总结笔记
0 0
猿创征文|Android常用知识总结
猿创征文|Android常用知识总结
0 0
关于Android SurfaceView截屏总结
关于Android SurfaceView截屏总结
0 0
Android获取启动页面Activity方法总结
我们在做Android自动化测试过程中,经常会需要获取应用的启动Activity页面信息,那么今天就来跟大家分享一下有哪些获取应用启动Activity页面信息的方法。
0 0
【原理+实战+视频+源码】6年老Android面经总结,实战篇
【原理+实战+视频+源码】6年老Android面经总结,实战篇
0 0
优秀Android程序员必知必会的网络基础,积累总结
优秀Android程序员必知必会的网络基础,积累总结
0 0
你还在把Java当成Android官方开发语言吗?积累总结
你还在把Java当成Android官方开发语言吗?积累总结
0 0
mmkv跨进程,Android开发经验的有效总结,系列篇
mmkv跨进程,Android开发经验的有效总结,系列篇
0 0
+关注
kylinarm
搬砖于造轮
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Android组件化实现
立即下载
蚂蚁聚宝Android秒级编译—— Freeline
立即下载
Android插件化:从入门到放弃
立即下载