Android自定义控件坐标系解析
自定义控件要想彻底的把握,掌握Android各种坐标系及一些API的坐标含义毫无疑问是不可忽视的技能,对于控件的摆放位置、触摸点、控件绘制等都离不开坐标系,所以学习自定义控件之前我们就先来谈一下Android坐标系。
一、Android屏幕坐标系和数学坐标系的区别
(1)、在数学坐标系中以xy轴的交点为坐标原点,x轴向右为正方向,y轴向上为正方向,这对于童鞋们来说已经再熟悉不过了,如图:
(2)、而在手机屏幕上的坐标系与数学坐标系还是有差别的,移动设备一般定义屏幕左上角为坐标原点,x轴向右为正方向,y轴向下为正方向,如图:
二、Android屏幕区域的划分
Android屏幕区域主要划分为五个区域分别为:状态栏区域、ActionBar区域、View布局区域、应用程序App区域、屏幕区域,相互之间又存在嵌套关系。如图所示:
下面我们来看看各个区域高度的获取:
(1)、状态栏区域高度获取:
//第一种方式,使用此方法一定要等界面渲染结束
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
//第二种方式,获取状态栏高度
Resources resources = this.getResources();
int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
int height = resources.getDimensionPixelSize(resourceId);//此次获取状态栏高度
//第三种方式,通过反射方式获取状态栏高度
int statusHeight = -1;
try {
Class clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int intheight = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
//获取状态栏高度
statusHeight = this.getResources().getDimensionPixelSize(intheight);
} catch (Exception e) {
e.printStackTrace();
}
(2)、ActionBar区域高度获取:
//第一种方式,此方法要等界面渲染结束
int actionBarHeight = getSupportActionBar().getHeight();
//第二种方式
TypedValue tv = new TypedValue();
if (this.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
int actionBarHeightOther = TypedValue.complexToDimensionPixelSize(
tv.data, this.getResources().getDisplayMetrics());
}
(3)、View布局区域高度获取:
//第一种方式
Rect rect = new Rect();
getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);
//第二种方式
//可见当执行onResume和onPause时,onWindowFocusChanged都会被调用。此时界面已渲染结束
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int width = view.getMeasuredWidth();//获得宽度
int height = view.getMeasuredHeight();//获得高度
}
}
//第三种方式
view.post(new Runnable() {
public void run() {
int width=view.getMeasuredWidth();
int height=view.getMeasuredHeight();
}
})
//第四种方式
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int width=view.getMeasuredWidth();
int height=view.getMeasuredHeight();
}
});
(4)、应用程序App区域高度获取:
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
(5)、屏幕区域高度获取:
//第一种方式,该方式在4.1版本后已过时。
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
//第二种方式
Display defaultDisplay = getWindowManager().getDefaultDisplay();
Point point = new Point();
defaultDisplay.getSize(point);
int x = point.x;
int y = point.y;
//第三种方式
Rect outSize = new Rect();
getWindowManager().getDefaultDisplay().getRectSize(outSize);
int left = outSize.left;
int top = outSize.top;
int right = outSize.right;
int bottom = outSize.bottom;
//第四种方式
DisplayMetrics outMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
int widthPixels = outMetrics.widthPixels;
int heightPixels = outMetrics.heightPixels;
//第五种方式
Point outSizeOther = new Point();
getWindowManager().getDefaultDisplay().getRealSize(outSizeOther);
int x1 = outSizeOther.x;
int y1 = outSizeOther.y;
//第六种方式
DisplayMetrics outMetrics1 = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics1);
int widthPixel = outMetrics1.widthPixels;
int heightPixel = outMetrics1.heightPixels;
特别注意:上面这些方法最好在Activity的onWindowFocusChanged()方法或者之后调用,因为只有这时候才是真正的显示完全。
三、Android坐标系的分类
上面我们分析了Android屏幕区域的划分,接着我们分析一下与区域相关的Android坐标系,在Android坐标系中可以分为:屏幕坐标系,视图坐标系。
(1)、屏幕坐标系
屏幕坐标系我们前面在和数学坐标系的区别已经介绍过了,以屏幕左上角为坐标原点,x轴向右为正方向,y轴向下为正方向,如图所示:
(2)、视图坐标系
视图坐标系在View绘制过程中,绘制的内容将以坐标系作为参考,最后确定绘制内容在View里面的位置。
下面我们来看看常用的坐标方法,注意这些方法是相对父容器而言的:
View相关方法 | 方法说明 |
view.getLeft() | 当前View的左边缘与它父View的左边缘的距离(视图坐标); |
view.getRight() | 当前View的右边缘与它父View的左边缘的距离(视图坐标); |
view.getTop() | 当前View的上边缘与它父View的上边缘(顶部)的距离(视图坐标); |
view.getBottom() | 当前View的下边缘与它父View的上边缘(顶部)的距离(视图坐标); |
View.getTranslationX() | 当前View在X轴的偏移量。初始值为0,向左偏移值为负,向右偏移值为正;(常见于属性动画中) |
View.getTranslationY() | 当前View在Y轴的偏移量。初始值为0,向上偏移为负,向下偏移为正;(常见于属性动画中) |
View.getX | 当前View在X轴的偏移量。初始值为0,向左偏移值为负,向右偏移值为正;返回值为getLeft()+getTranslationX(),当setTranslationX()变getLeft()不变时,getX()变。 |
View.getY | 当前View在Y轴的偏移量。初始值为0,向上偏移为负,向下偏移为正;返回值为getTop()+getTranslationY(),当setTranslationY()变getTop()不变时,getY()变。 |
为了解释清楚这些方法,准备了张图,如图所示:
此时我们可以获取视图(View)宽高的方法:
View宽高方法 | 方法说明 |
getWidth() | 当前View的宽度,即getRight()-getLeft() |
getHeight() | 当前View宽度,即getBottom()-getTop() |
需要注意的是使用以上方法的过程中要在View测量结束即渲染完成后,不然获取到的值为0。
我们再来看看手指触摸屏幕时MotionEvent提供的一些方法解释:
MotionEvent坐标方法 | 方法说明 |
getX() | 触摸中心点与该View左边缘的距离(相对坐标) |
getY() | 触摸中心点与该View上边缘的距离(相对坐标) |
getRawX() | 触摸中心点与屏幕左边缘的距离(绝对坐标) |
getRawY() | 触摸中心点与屏幕上边缘的距离(绝对坐标) |
为了解释清楚这些方法,准备了张图,如图所示:
今天的内容就到这啦,本文主要就是阐述View里常用方法及坐标相关的概念,也是为后期的内容做铺垫。