09.View位置&坐标信息
坐标系&View 位置&坐标信息
Android 坐标系
Android 屏幕坐标系
Android 坐标系可以看成是物理存在的坐标系,也可以理解为绝对坐标,以屏幕为参照物,就是以屏幕的左上角是坐标系统原点(0,0),原点向右延伸是 X 轴正方向,原点向下延伸是 Y 轴正方向。比如系统的 getLocationOnScreen(int[] location) 实际上获取 Android 坐标系中位置(即该 View 左上角在 Android 坐标系中的坐标),还有 getRawX()、getRawY() 获取的坐标也是 Android 坐标系的坐标。
视图坐标系
视图坐标系是相对坐标系,是以父视图为参照物,以父视图的左上角为坐标原点(0,0),原点向右延伸是 X 轴正方向,原点向下延伸是 Y 轴正方向,getX()、getY() 就是获取视图坐标系下的坐标。
绘图坐标系 draw
Canvas 的 drawXXX 方法中传入的各种坐标指的都是绘图坐标系中的坐标,而非 Canvas 坐标系中的坐标。默认情况下,绘图坐标系与 Canvas 坐标系完全重合,即初始状况下,绘图坐标系的坐标原点也在 View 的左上角,从原点向右为 x 轴正半轴,从原点向下为 y 轴正半轴。
但不同于 Canvas 坐标系,绘图坐标系并不是一成不变的,可以通过调用 Canvas 的 translate 方法平移坐标系,可以通过 Canvas 的 rotate 方法旋转坐标系,还可以通过 Canvas 的 scale 方法缩放坐标系,而且需要注意的是,translate
、rotate
、scale
的操作都是基于当前绘图坐标系的,而不是基于 Canvas 坐标系,一旦通过以上方法对坐标系进行了操作之后,当前绘图坐标系就变化了,以后绘图都是基于更新的绘图坐标系了。也就是说,真正对我们绘图有用的是绘图坐标系而非 Canvas 坐标系。
子 View 获取自身尺寸信息
- getHeight():获取 View 自身高度
- getWidth():获取 View 自身宽度
子 View 获取自身坐标信息
子 View 的存在是依附于父 View 的,所以用的是相对坐标来表示
与 margin 有关;padding 无关?;软键盘弹出调整布局不会影响该值
- int getLeft():获取子 View 自身左边到其父 View 左边的距离
- int getTop():获取子 View 自身顶边到其父 View 顶边的距离
- int getRight():获取子 View 自身右边到其父 View 左边的距离
- int getBottom():获取子 View 自身底边到其父 View 顶边的距离
- int getPaddingXxxx:获取子 View 内部的内容的边框距离子 View 的边框的距离即内边距,Xxxx 代表 Left、Right、Top、Bottom。
- float getScrollX/Y() // view 相对于 ‘ 坐标系统原点 ‘ 在 X/Y 轴上的偏移量,如 ScrollView 往上滚动了一段超出屏幕的距离,就是 mScrollY。
获取 MotionEvent 中对应坐标信息
- getX():获取 Touch 事件当前触摸点距离控件左边的距离,即视图坐标下对应的 X 轴的值
- getY():获取 Touch 事件距离控件顶边的距离,即视图坐标系下对应的 Y 轴的值
- getRawX():获取 Touch 事件距离整个屏幕左边距离,即绝对坐标系下对应的 X 轴的值
- getRawY():获取 Touch 事件距离整个屏幕顶边的的距离,即绝对坐标系下对应的 Y 轴的值
获取 view 在屏幕中的位置
如果在 Activity 的 OnCreate() 事件输出那些参数,是全为 0,要等 UI 控件都加载完了才能获取到这些。
在onWindowFocusChanged(boolean hasFocus)
中获取为好。
getLocalVisibleRect 和 getGlobalVisibleRect
getLocalVisibleRect(Rect r)
返回一个填充的 Rect 对象,所有的 View 都是以一块矩形内存空间存在的
当 View
可见时,以自身 View
左上角为参考系,坐标系的原点为 View
自己的坐标原点。当 View
不可见时,以父控件左上角为参考系,坐标系的原点为 View
的父控件的坐标原点。
getGlobalVisibleRect(Rect r)
获取 Android 坐标系的一个视图区域,返回一个填充的 Rect 对象且该 Rect 是基于总整个屏幕的
是以屏幕左上角为参考系,判断 view
有一部分在屏幕中,返回 true
(没有被父 View
遮挡)。反之,如果它全部被父 View
遮挡住或者本身就是不可见的,返回 false
。
测试
为了更好理解,Demo 如下:(测试机分辨率为 720*1440
,橙红色 view 为 400*400px
。布局为一个 RelativeLayout
嵌套这 TextView
)
屏幕包含状态栏,高度为 55px,所以计算的结果要考虑到这个问题。
- 当
Textview
设置marginLeft="100px"
、marginTop="100px"
时: - 当
Textview
设置marginRight="-100px"
、marginBottom="-100px"
时:
下面的理解主要针对 getLocalVisibleRect(rect), View 不可见的情况:
- 当
Textview
设置marginTop="-500px"
时,此时TextView
是在屏幕外的:此时的getLocalVisibleRect(rect)
,坐标系的原点为它的父控件的坐标原点,也就是外面嵌套的 RelativeLayout,RelativeLayout 的宽高都是 match_parent 的,所以他的数值跟 getGlobalVisibleRect(rect) 是相同的。
当 Textview 设置 layout_marginBottom=”-500px”,layout_marginRight=”-500px”,都在父布局的底部时,此时 TextView 是在屏幕外的:
高度要考虑底部虚拟导航栏,高度为 55px,所以计算的结果要考虑到这个问题。
此时的 getLocalVisibleRect(rect),坐标系的原点为它的父控件的坐标原点,也就是外面嵌套的 RelativeLayout,RelativeLayout 的宽高都是 match_parent 的,所以他的数值跟 getGlobalVisibleRect(rect) 是相同的。
TextView
的宽、高为 400px, layout_marginBottom="-500px"
,layout_marginRight="-500px"
,所以 TextView
距离屏幕右间距为 100px,距离屏幕下间距为 100px,
考虑到下部虚拟导航栏高度为 55px,所以 TextView
距离屏幕底部实际距离为(100px-55px)=45px
左面:720+100 =820px
上面:1440+45=1485px
右面:720+100+400 =1220px
下面:1440+45+400 =1885px
应用
判断 View1 是否在某个 View2 可视区域内
当使用 getLocalVisibleRect(rect)
时,当 View 不在可视区域内时:
在顶部,Rect.top <0
在底部,Rect.bottom>View2.getHeight
所以:
1
2
3
4
5
fun isCover(activity: Activity, view1: View, view2: View): Boolean {
val rect = Rect()
view1.getLocalVisibleRect(rect)
return !(rect.top<0||rect.bottom>view2.height)
}
判断 View 可视区域占其自身百分比(当 view1 开始可视后调用,否则一直都是 100%)
1
2
3
4
5
6
7
8
fun getVisibilePercent(activity: Activity, view1: View): Int {
val rect = Rect()
view1.getLocalVisibleRect(rect)
Log.e("测试","rect.height ="+rect.height().toString() + " view1.height ="+view1.height)
val a = rect.height() * 100 / view1.height
Log.e("测试",a.toString())
return a
}
判断 View 是否显示出现在屏幕上
1
2
3
4
5
6
7
fun isCoverScreen_LocalVisibleRect(view1: View): Boolean {
val screenWidth = CFUtil.getScreenWidth()//获取屏幕宽度
val screenHeight = CFUtil.getScreenHeight()//获取屏幕高度
val rect = Rect()
view1.getLocalVisibleRect(rect)
return !(rect.top<0||rect.bottom>screenHeight)
}
总结
getGlobalVisibleRect(rect)
简单来说就是目标view
在父view
的映射,然后从屏幕左上角开始计算,保存到rect
中,注意是父view
,而不是屏幕,因为 demo 的父view
(RelativeLayout
) 和屏幕宽高是一样的。getLocalVisibleRect(rect)
只要这个View
的左上角在屏幕中,它的LocalVisibleRect
的左上角坐标就一定是 (0,0),如果View
的在右下角屏幕中,它的LocalVisibleRect
右下角坐标就一定是 (view.getWidth()
,view.getHeight()
)。
如果不在屏幕中,他的Rect
数值就跟getGlobalVisibleRect(rect)
是一样的。
getLocationOnScreen
getLocationOnScreen(int[] outLocation)
计算该视图在 Android 坐标系中的 x,y 值,获取在当前屏幕内的绝对坐标(这个值是要从屏幕顶端算起,当然包括了通知栏和状态栏的高度)
1
2
3
int[] location = new int[2];
view.getLocationOnScreen(location);
// location [0]--->x坐标,location [1]--->y坐标
getLocationInWindow
public void getLocationInWindow(@Size(2) int[] outLocation)
计算该视图在它所在的 widnow 的坐标 x,y 值,获取在整个 window 的绝对坐标
1
2
3
4
int[] location = new int[2];
public void getLocationInWindow(@Size(2) int[] outLocation)
view在坐标系统的位置
// location [0]--->x坐标,location [1]--->y坐标
getLocationOnScreen 和 getLocationInWindow 区别
https://stackoverflow.com/a/20154562
主要区别
- getLocationOnScreen() 将根据手机屏幕获取位置。
- getLocationInWindow() 将根据活动窗口获取位置。
对于 x 坐标,两种方法的值通常相同;对于 y 坐标,这些值对于状态栏的高度有差异
正常的 Activity 活动窗口是和全屏一样,在 z-order
摆在 statusbar 下面,而不是 y-order
,这种情况 2 种获取的时是一样的。
1
2
3
4
5
|--phone screen-----activity window---|
|--------status bar-------------------|
| |
| |
|-------------------------------------|
public void getLocationOnScreen(@Size(2) int[] location)
// 该方法可以获取到当前 view 与屏幕的关系,location(0) 代表 X 值,表示该 view 的左边缘与屏幕的左边缘之间的距离。可以想象,当滑屏产生,view 开始移动该值肯定会改变的。location(1) 代表 Y 值,表示该 view 的上边缘与屏幕的上边缘之间的距离,该距离肯定是包含标题栏的高度的。public void getLocationInWindow(@Size(2) int[] location)
// 当 View.getLocationInWindow() 和 View.getLocationOnScreen() 在 window 占据全部 screen 时,返回值相同,不同的典型情况是在 Dialog 中时。当 Dialog 出现在屏幕中间时,View.getLocationOnScreen() 取得的值要比 View.getLocationInWindow() 取得的值要大
dialog
View.getLocationInWindow() 和 View.getLocationOnScreen() 在 window 占据全部 screen 时,返回值相同,不同的典型情况是在 Dialog 中时。当 Dialog 出现在屏幕中间时,View.getLocationOnScreen() 取得的值要比 View.getLocationInWindow() 取得的值要大。
全屏
- 未沉浸到状态栏
- 沉浸到状态栏
View#getWindowVisibleDisplayFrame
获取窗口可视区域大小
- public void getWindowVisibleDisplayFrame(Rect outRect)
参数 outRect:获取到的区域填充到 outRect 中
- 获取 View 可见区域的 Rect,left/right/top/bottom 值为坐标(相对于屏幕左上角,包括状态栏);如果 View 没有 attach 到 window,那么是 raw display size。
- 该操作需要 IPC,会影响一定性能,如 draw 不应该获取
1
2
val outRect = Rect()
contentViewChild.getWindowVisibleDisplayFrame(outRect)
Ref
Android 屏幕信息获取
- Activity.getWindowManager().getMetrics(mDisplayMetrics)
- Context.getResources().getDisplayMetrics()
- Activity.getWindowManager().getDefaultDisplay()
- window.decorView.getWindowVisibleDisplayFrame(rect)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class 屏幕适配基础 : AppCompatActivity() {
var sb = StringBuilder()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_screen_support_base)
getScreenDensity_ByWindowManager()
getScreenDensity_ByResources()
getDefaultScreenDensity()
val realDm = DisplayMetrics()
windowManager.defaultDisplay.getRealMetrics(realDm)
val width = realDm.widthPixels
val height = realDm.heightPixels
//
val rect = Rect()
window.decorView.getWindowVisibleDisplayFrame(rect)
sb.append("WindowVisibleDisplayFrame,top: ${rect.top}, bottom: ${rect.bottom}\n")
sb.append("通过Rect计算得出状态栏高度:${rect.top} ,虚拟导航栏高度:${height - rect.bottom} \n")
tv_result.text = sb.toString()
}
//获得手机的宽度和高度像素单位为px
// 通过WindowManager获取
fun getScreenDensity_ByWindowManager() {
var mDisplayMetrics = DisplayMetrics() //屏幕分辨率容器
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics)
// 去除状态栏的
var width = mDisplayMetrics.widthPixels
var height = mDisplayMetrics.heightPixels
var density = mDisplayMetrics.density
var densityDpi = mDisplayMetrics.densityDpi
sb.append("屏幕尺寸(通过WindowManager):$height x $width ,density:$density ,densityDpi:$densityDpi \n")
}
// 通过Resources获取
fun getScreenDensity_ByResources() {
var mDisplayMetrics = getResources().getDisplayMetrics();
// 去除状态栏的
var width = mDisplayMetrics.widthPixels;
var height = mDisplayMetrics.heightPixels;
var density = mDisplayMetrics.density;
var densityDpi = mDisplayMetrics.densityDpi;
sb.append("屏幕尺寸(通过Resources):$height x $width ,density:$density ,densityDpi:$densityDpi \n")
}
// 获取屏幕的默认分辨率
fun getDefaultScreenDensity() {
var mDisplay = getWindowManager().getDefaultDisplay();
var width = mDisplay.getWidth();
var height = mDisplay.getHeight();
// 去除状态栏的
var size = Point()
mDisplay.getSize(size)
// 没有去除状态栏的
var realsize = Point()
mDisplay.getRealSize(realsize)
// 去除状态栏的
val dm = DisplayMetrics()
mDisplay.getMetrics(dm)
// 没有去除状态栏的
val realdm = DisplayMetrics()
mDisplay.getRealMetrics(realdm)
sb.append("屏幕尺寸(通过getDefaultDisplay)size:${size.y} x ${size.x} | realsize: :${realsize.y} x ${realsize.x} | " +
" dm:$dm | realdm:$realdm \n")
}
}
View#getWindowVisibleDisplayFrame
获取窗口可视区域大小。
方法原型:
1
public void getWindowVisibleDisplayFrame(Rect outRect);
它接受一个 Rect 对象作为参数,执行过程中会根据当前窗口可视区域大小更新 outRect 的值,执行完毕后,就可以根据更新后的 outRect 来确定窗口可视区域的大小。所以正如 outRect 的名字所见,它是一个输出参数。
1
2
Rect rect = new Rect();
view.getWindowVisibleDisplayFrame(rect); // 后面调用rect获取值
总结
- 获取当前窗口可视区域大小 Rect(相对于屏幕左上角坐标系统)
- 和具体的 View 无关(随便什么 view);与 View 的 visible 和 gone 无关;margin 无关;只与 View 是否 attach 有关
- 受全屏,状态栏、虚拟导航栏和软键盘状态影响
- 通过 IPC 方式从 window manager 中获取到这个信息的,相对来说它的开销会比较大,因此不适合放在对性能要求很高的地方调用,例如 View 绘制的代码中。
应用
- 获取软键盘高度;软键盘是否显示
- 状态栏高度
注意
1、getWindowVisibleDisplayFrame() 的执行结果和 View 对象选取的关系
getWindowVisibleDisplayFrame() 方法的返回结果和该窗口中选取的 View 并没有关系。在某个时刻,使用当前窗口中的任意 View 执行 getWindowVisibleDisplayFrame() 返回的结果都是一样的。一般用布局根 view 或者 android.R.id.content
来获取。
1
2
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
或者
1
2
3
val contentView = activity.findViewById<FrameLayout>(android.R.id.content)
val outRect = Rect()
contentView.getWindowVisibleDisplayFrame(outRect)
由于 getWindowVisibleDisplayFrame() 方法是用来获取某个窗口的可视区域大小,所以调用 getWindowVisibleDisplayFrame() 方法的 View 必须包含在该窗口中,如果是一个孤立的 View,或者包含在其他窗口中,是没有意义的。例如:
1
2
3
Rect rect = new Rect();
// 这个new出来的View并没有add到任何窗口上,所以调用它的getWindowVisibleDisplayFrame()方法是没有意义的。
new View(this).getWindowVisibleDisplayFrame(rect);
2、getWindowVisibleDisplayFrame() 的执行结果和 View 对象状态的关系
虽然 getWindowVisibleDisplayFrame() 的执行结果和窗口中 View 的选取没有关系,但是却和执行此方法时 View 的状态有关。由于此方法是用来获取窗口的可视区域大小,所以如果调用此方法时,调用的 View 对象还没有附着(attach)到任何 Window 上,那么执行此方法将不会得到实际的某个窗口的可视区域大小,只有 View 对象已经 attach 到 Window 上之后,调用此方法才能得到真实的窗口的可视区域大小。当调用的 View 对象还没有 attach 到 Window 时,getWindowVisibleDisplayFrame() 方法会估计出一个可能的可视区域大小,这个大小通常是设备的屏幕尺寸(以像素为单位),由于它并不代表真实的窗口可视区域大小,所以这个数值的意义不大。
由于在 Activity/Fragment/Dialog 的 onCreate() 方法中,View 对象还没有 attach 到 Window 上,所以在 onCreate() 方法中执行某个 View 的 getWindowVisibleDisplayFrame() 方法,是不会得到当前 Window 实际的可视区域大小的。
在 Activity 的 onAttachedToWindow() 方法中执行 getWindowVisibleDisplayFrame(),也是得不到当前 Window 实际的可视区域大小的。因为 Activity 的 onAttachedToWindow() 方法执行时,表示当前 Window 被 attach 到 window manager 中,Window 中的 View 仍然没有 attach 到 Window 上。
View attach 到 Window 之后,View 对象的 onAttachedToWindow() 方法会被执行,理论上来说,在自定义 View 的 onAttachedToWindow() 方法中执行 getWindowVisibleDisplayFrame() 应该可以得到当前 Window 实际的可视区域大小,但实际情况却并非如此。在自定义 View 的 onAttachedToWindow() 方法中执行 getWindowVisibleDisplayFrame() 会概率性的出现不同的结果,有时返回的 rect 对象大小是 0,有时则是设备的屏幕尺寸,但都不是当前 Window 实际的可视区域大小。具体原因未知,没有仔细研究。所以,也不要在 View 对象的 onAttachedToWindow() 方法中执行 getWindowVisibleDisplayFrame()。
要想得到当前 Window 实际的可视区域大小,可以在 Activity/Fragment/Dialog 的 onWindowFocusChanged() 方法中执行 getWindowVisibleDisplayFrame()。这时 Window 中的 View 对象都已经 attach 到 Window 上。
还有一点需要说明的是,getWindowVisibleDisplayFrame() 的执行结果和 View 是否可见没有关系。View 无论是 VISIBLE,还是 INVISIBLE 或者 GONE,对 getWindowVisibleDisplayFrame() 的执行结果没有影响。当 View 是 INVISIBLE 的时候,其 onDraw() 方法不会被调用,当 View 是 GONE 的时候,其 onDraw() 和 onLayout() 方法不会被调用。但无论是 INVISIBLE 或者 GONE,onAttachedToWindow() 都会被调用,也就是说 View 会被 attach 到 Window 上,所以即使 View 是 INVISIBLE 或者 GONE 的,getWindowVisibleDisplayFrame() 也能够正确的返回。
3、系统 Inset(状态栏、虚拟导航栏、软键盘) 对 getWindowVisibleDisplayFrame() 的执行结果的影响
状态栏(StatusBar)
- 全屏
如果窗口是全屏的,也就是设置了 flags 为WindowManager.LayoutParams.FLAG_FULLSCREEN
,或者android:windowFullscreen
设置为 true,则 outRect 中的 top 属性不受状态栏影响,其值始终为 0。 - 非全屏
如果窗口的 LayoutParams 的 height 设置为WindowManager.LayoutParams.MATCH_PARENT
,则 outRect 中的 top 值会等于系统状态栏的高度;
如果窗口的 LayoutParams 的 height 设置为WindowManager.LayoutParams.WRAP_CONTENT
或者某个具体的值,则 outRect 中的 top 值会等于系统状态栏和窗口重叠区域的高度,如果没有重叠,则是 0,例如,屏幕高度为 1920,窗口高度设置为 1900,窗口居中显示。这时窗口上下距离屏幕各有 10 个像素的距离。
假如系统状态栏高度为 60,窗口和状态栏的重叠区域的高度就是 50。因此,getWindowVisibleDisplayFrame() 返回的 outRect 中的 top 值为 50。
虚拟导航栏 NavigationBar
这里只考虑软键盘是隐藏的情况,如果软键盘是显示的,则软键盘和虚拟按键栏对 outRect 中的 bottom 属性的值的影响将会叠加。
如果虚拟按键栏是隐藏的,则 outRect 中的 bottom 属性的值将始终等于屏幕高度。如果虚拟按键是显示的,outRect 中的 bottom 属性的值将等于屏幕高度减去理论上虚拟按键会对窗口位置产生的影响。如果窗口高度是 MATCH_PARENT 的,则 outRect 中的 bottom 属性的值将等于屏幕高度减去虚拟按键的高度。
软键盘(虚拟键盘 SoftInput/Keyboard)
如果软键盘是隐藏的,则 outRect 中的 bottom 属性的值将始终等于屏幕高度(实际上还要减去虚拟导航栏的高度,这里先忽略虚拟导航栏)。如果软键盘是显示的,outRect 中的 bottom 属性的值将等于屏幕高度减去理论上虚拟键盘会对窗口位置产生的影响。如果窗口高度是 MATCH_PARENT 的,则 outRect 中的 bottom 属性的值将等于屏幕高度减去虚拟键盘的高度。
同样的例子,屏幕高度为 1920,窗口高度设置为 1900,窗口居中显示。这时窗口上下距离屏幕各有 10 个像素的距离。假如虚拟键盘高度为 600,窗口和虚拟键盘的重叠区域的高度就是 590。因此,getWindowVisibleDisplayFrame() 返回的 outRect 中的 bottom 值为 1920 - 590。
4、对话框大小
getWindowVisibleDisplayFrame() 的结果并不是该窗口实际的大小(虽然它和窗口的大小有一定关系)。例如一个居中显示的对话框,它的实际高度只有 500px,它和系统状态栏,系统软键盘,系统虚拟按键栏都没有重叠,那么 getWindowVisibleDisplayFrame() 的结果就是设备的尺寸大小,而不是该对话框的实际大小。
5、View 的 Visible 和 Gone
虽然方法名字中有一个 Visible,但是 getWindowVisibleDisplayFrame() 的结果并不受该窗口是否在被其他窗口遮挡的影响。即使该窗口已经被切换到后台,只要该窗口还没有 detach,getWindowVisibleDisplayFrame() 的结果就不会变化。
Android 判断触摸点是否在某个 view 的区域,解决子 view 与 parent 的 touch 事件冲突
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//(x,y)是否在view的区域内
private boolean isTouchPointInView(View view, int x, int y) {
if (view == null) {
return false;
}
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
//view.isClickable() &&
if (y >= top && y <= bottom && x >= left
&& x <= right) {
return true;
}
return false;
}
Rect 和 RectF
Rect 类
- 定义
表示坐标系中的一块矩形区域,没有边界检查,caller 必须保证 left<=right,top<=bottom - 构造
public Rect(int left, int top, int right, int bottom) - 参数 new Rect(150, 75, 260, 120)
1
2
3
4
left:矩形左边的X坐标,
top:矩形顶部Y的坐标
right:矩形右边X的坐标
bottom:矩形底部Y的坐标
其实就是左上角的坐标是(150,75),右下角的坐标是(260,120)
注意:右下角 (260,120) 并不在这个矩形里面,左上角在。实际矩形区域 [150,75,260,120)。但 Rect 计算出的 Height 和 Width 倒是对的。所以,在此告诫各位程序员,在涉及 Rect 运算的时候,尽量不要使用它的右下角左边,即 right 和 bottom。因为他们是错的。当然,在你调用 android 自己的函数时,是可以使用的,因为 Android 里面一直保持这么奇葩的思维。
Rect 和 RectF 区别
1、精度不一样,Rect 是使用 int 类型作为数值,RectF 是使用 float 类型作为数值
2、两个类型提供的方法也不是完全一致
- Rect:
equals(Object obj)
exactCenterX() 返回X和Y的中心
exactCenterY()flattenToString()
toShortString()``unflattenFromString(String str)`
- RectF
round(Rect dst)
roundOut(Rect dst)
set(Rect src)
TouchDelegate
见 [[TouchDelegate 扩大事件区域]]