1.getLocationInWindow和getLocationOnScreen
①一个控件在其父窗口中的坐标位置
View.getLocationInWindow(int[] location)
一个控件在其整个屏幕上的坐标位置,注意这个值要从屏幕顶端算起,也就是包括了通知栏的高度。
View.getLocationOnScreen(int[] location)
getLocationInWindow是以B为原点的C的坐标
getLocationOnScreen以A为原点。
注意:在Activity的onCreate()方法里获取这些值时,全为0,要等UI控件都加载完了才能获取到。因此在onWindowFocusChanged(boolean hasFocus)中获取为好。
②getLocationOnScreen示例:
start = (Button) findViewById(R.id.start);
int []location=new int[2];
start.getLocationOnScreen(location);
int x=location[0];//获取当前位置的横坐标
int y=location[1];//获取当前位置的纵坐标
getLocationInWindow示例:
start = (Button) findViewById(R.id.start);
int []location=new int[2];
start.getLocationInWindow(location);
int x=location[0];//获取当前位置的横坐标
int y=location[1];//获取当前位置的纵坐标
③源码
View.getLocationInWindow(int[] location):
/** Computes the coordinates of this view in its window. The argument must be an array of two integers. After the method returns, the array contains the x and y location in that order. */
public void getLocationInWindow(int[] location){
if (location == null || location.length < 2) {
throw new IllegalArgumentException( "location must be an array of two integers");
}
if (mAttachInfo == null) {
// When the view is not attached to a window, this method does not make sense
location[0] = location[1] = 0;
return;
}
float[] position = mAttachInfo.mTmpTransformLocation;
position[0] = position[1] = 0.0f;
if (!hasIdentityMatrix()) {
getMatrix().mapPoints(position);
}
position[0] += mLeft;
position[1] += mTop;
ViewParent viewParent = mParent;
while (viewParent instanceof View) {
final View view = (View) viewParent;
position[0] -= view.mScrollX;
position[1] -= view.mScrollY;
if (!view.hasIdentityMatrix()) {
view.getMatrix().mapPoints(position);
}
position[0] += view.mLeft;
position[1] += view.mTop;
viewParent = view.mParent;
}
if (viewParent instanceof ViewRootImpl) {
final ViewRootImpl vr = (ViewRootImpl) viewParent;
position[1] -= vr.mCurScrollY;
}
location[0] = (int) (position[0] + 0.5f);
location[1] = (int) (position[1] + 0.5f);
}
View.getLocationOnScreen(int[] location):
/**Computes the coordinates of this view on the screen. The argument must be an array of two integers. After the method returns, the array contains the x and y location in that order. */
public void getLocationOnScreen(int[] location){
getLocationInWindow(location);
final AttachInfo info = mAttachInfo;
if (info != null) {
location[0] += info.mWindowLeft;
location[1] += info.mWindowTop;
}
}
2.View.getLocalVisibleRect
Android开发中有时候需要对View的可见性进行判断,常见的有:
public int View.getVisibility();
public boolean View.isShown();
但是这些只能简单的判断这个View是否可见,有时候需要更复杂的功能,比如View的可见区域占其自身的百分比等,常见需求为滚动视频列表时当滑出屏幕外一定百分比时暂停播放等。
这时候可以使用View.getLocalVisibleRect(Rect rect)。这个方法会返回View的可视区域的Rect对象。它有如下注意项:
①当View可见时,无论是否完全可见,Rect内的坐标所在坐标系的原点为View自己的坐标原点。
②当View不可见时,Rect内的坐标所在坐标系的原点为View的父控件的坐标原点。
(1)View可见
①部分可见,底部滑入
rect:left=0,top=0,right=990,bottom=150;
因为View可见时是以自己为坐标系计算的,所以left和top都为0,right为自身宽度,bottom为可视区域高度
②部分可见,顶部滑出
rect:left=0,top=150,right=990,bottom=300;
因为View可见时是以自己为坐标系计算的,所以left为0,top为滑出ScrollView的高度150,right为自身宽度,bottom为View自身高度。
③完全可见
rect:left=0,top=0,right=990,bottom=300;
因为View可见时是以自己为坐标系计算的,所以left和top都为0,right为自身宽度,bottom为View自身高度。
(2)不可见
①在底部
rect:left=15,top=2060,right=1005,bottom=2360
因为View不可见时是以父控件为坐标系计算的
ScrollView的高度为1860,加上View与ScrollView的距离200,所以top=2060
left为View与ScrollView的margin,所以left为15
right和bottom分别为加上View的宽度和高度
②在顶部
rect:left=15,top=-500,right=1005,bottom=-200;
通过以上分析,可以判断View是否在可视区域内:
当View不在可视区域内时,
在顶部,Rect.top <0
在底部,Rect.bottom>View.getHeight
所以
public boolean isVisible(Rect rect){
return !(rect.top<0||rect.bottom>getHeight());
}
还可以判断View可视区域占其自身百分比:
public int getVisibilePercent(Rect rect){
return rect.height() * 100 / getHeight();
}