Android 自定义View之坐标系(一)

前言

本文主要阐述的是Android坐标系,便于对于Android视图界面坐标的一个简单了解。在Android任何视图中,不管是对于控件的摆放位置、触摸点、自定义控件绘制等等都脱离不开坐标系。Android坐标系是一个三维坐标,Z轴向上,X轴向右,Y轴向下。这三维坐标的点处理就能构成Android丰富的界面或者动画等效果,所以Android坐标系在整个Android界面中的重要性就不言而喻。

Android屏幕区域划分

在Android坐标系前,我们先来了解一下Android屏幕的区域划分。Android屏幕的区域主要分为五个区域分别为:状态栏区域、ActionBar区域、View布局区域、应用程序区域、屏幕区域,当相互之间又存在嵌套关系。具体如下图:
在这里插入图片描述
通过上图依次列出区域的一些坐标或者度量方式:

状态栏高度获取

	
	//第一种方式
	//该方法依赖于WMS(窗口管理服务的回调),使用此方法一定要等界面渲染结束
	Rect rect= new Rect();
	getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
	int statusBarHeight = rectangle.top;

	//第二种方式
	/**
     * 获取状态栏高度
     * @param context
     */
    Resources resources = context.getResources();
    int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
    int height = resources.getDimensionPixelSize(resourceId);//此次获取状态栏高度

	//第三种方式
	/**
     * 通过反射方式获取状态栏高度
     * @param context
     * @return
     */
    int statusHeight = -1;
    try{
        Class<!--?--> clazz = Class.forName("com.android.internal.R$dimen");
        Object object = clazz.newInstance();
        intheight = Integer.parseInt(clazz.getField("status_bar_height")
                .get(object).toString());
        statusHeight = context.getResources().getDimensionPixelSize(height);//此次获取状态栏高度
    }catch(Exception e) {
        e.printStackTrace();
    }

ActionBar高度获取


	//第一种方式
	int actionBarHeight = getActionBar().getHeight();
	
	//第二种方式
	TypedValue tv = new TypedValue();
	if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
		int actionBarHeight = TypedValue.complexToDimensionPixelSize(
															tv.data, 
															context.getResources().getDisplayMetrics());
	}

View布局区域


	//第一种方式
	Rect rect = new Rect();
	getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);

	//第二种方式
	//可见当执行onResume和onPause时,onWindowFocusChanged都会被调用。此时界面已渲染结束
	 @Override
	public void onWindowFocusChanged(boolean hasFocus) {
		super.onWindowFocusChanged(hasFocus);
		if (hasFocus) {
		    int width = view.getMeasuredWidth();//获得宽度
		    int height = view.getMeasuredHeight();//获得高度
		}
	}
	
	//第三种方式
	view.post(new Runnable() {
         @Override
         public void run() {
             int width=view.getMeasuredWidth();
             int height=view.getMeasuredHeight();
         }
     })
     
	//第四种方式
    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            int width=view.getMeasuredWidth();
            int height=view.getMeasuredHeight();
        }
    });

应用程序区域高度获取


	Rect rect = new Rect();
	getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

屏幕区域高度获取

	
	//第一种方式,该方式在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 outSize = new Point();
    getWindowManager().getDefaultDisplay().getRealSize(outSize);
    int x = outSize.x;
    int y = outSize.y;

	//第六种方式
    DisplayMetrics outMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics);
    int widthPixel = outMetrics.widthPixels;
    int heightPixel = outMetrics.heightPixels;

注意:在Activity的onCreate()或者onResume()中去获得View的高度的时候不能正确获得宽度和高度信息,这是因为 View的measure过程和Activity的生命周期不是同步执行的,因此无法保证Activity执行了onCreate、onStart、onResume时是否已经完成了界面测量,如果还没有测量完,那么获得的宽高就是0。

Android坐标系

前面我们通过图了解了一下Android屏幕的划分及相应区域尺寸的获取方式,那么接下里我们将分析一下与区域相关的Android坐标系。在Android中的坐标系可以分为三类:屏幕坐标系布局坐标系视图坐标系

屏幕坐标系
该坐标系是以屏幕的左上角为原点(0, 0), 水平向右代表 x 方向的正方向, 垂直向下代表 y方向的正方向。
在这里插入图片描述
布局坐标系
该坐标系是以View布局区域的左上角为坐标原点, 水平向右代表 x 方向的正方向,垂直向下代表 y 方向的正方向。
在这里插入图片描述
视图坐标系
该坐标系是在View绘制过程中,绘制的内容将该坐标系作为参考,来绘制View也就是内容在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,向左偏移值为负,向右偏移值为正;
View.getY当前View在Y轴的偏移量。初始值为0,向上偏移为负,向下偏移为证;

具体方法如下:
在这里插入图片描述
以下为视图(View)获取高宽方法:

View宽高方法方法说明
getWidth()当前View的宽度,即getRight()-getLeft()。
getHeight()当前View宽度,即getBottom()-getTop()。

注意:当在使用以上两个方法的时候一定要在View测量结束(渲染完成)后,不然获取到的值是不准确的(都为0)。

接下来将说明在View使用中MotionEvent类相关坐标方法说明(涉及到相对坐标和绝对坐标),相对坐标是相对View本身而言的,即在View范围内的触摸点到View上边缘和左边缘的距离;而绝对坐标是相对屏幕的,即在View范围内的触摸点到屏幕上边缘和左边缘的距离:

MotionEvent类相关坐标方法方法说明
getX()触摸中心点与该View左边缘的距离(相对坐标)
getY()触摸中心点与该View上边缘的距离(相对坐标)
getRawX()触摸中心点与屏幕左边缘的距离(绝对坐标)
getRawY()触摸中心点与屏幕上边缘的距离(绝对坐标)

具体方式如下图:
在这里插入图片描述

结束

对于坐标系本文就阐述到这里,本文介绍坐标系目的有两个:其一主要方便大家再次的了解Android坐标系及相关的API使用;其二为接下来即将阐述的自定义View做一个铺垫,因为坐标概念只是一个基础对于自定义View也是相当重要的一部。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TypeArray 是 Android 中的一个特殊的资源类型,用于在 XML 中声明自定义 View 的属性。使用 TypeArray 可以方便地在 XML 布局中指定 View 的属性,而不需要在 Java 代码中进行硬编码。 使用 TypeArray 的步骤如下: 1. 在 res/values/attrs.xml 文件中定义自定义 View 的属性。 ```xml <resources> <declare-styleable name="MyCustomView"> <attr name="customAttr1" format="integer" /> <attr name="customAttr2" format="string" /> <attr name="customAttr3" format="boolean" /> </declare-styleable> </resources> ``` 2. 在自定义 View 的构造函数中获取 TypedArray 对象,并从中获取属性值。 ```java public class MyCustomView extends View { private int customAttr1; private String customAttr2; private boolean customAttr3; public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView); customAttr1 = a.getInt(R.styleable.MyCustomView_customAttr1, 0); customAttr2 = a.getString(R.styleable.MyCustomView_customAttr2); customAttr3 = a.getBoolean(R.styleable.MyCustomView_customAttr3, false); a.recycle(); } } ``` 在上面的代码中,`context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)` 用于获取 TypedArray 对象,`R.styleable.MyCustomView` 是在 attrs.xml 文件中定义的自定义属性集合,`a.getInt()`、`a.getString()`、`a.getBoolean()` 用于从 TypedArray 对象中获取属性值,最后需要调用 `a.recycle()` 来回收 TypedArray 对象。 3. 在 XML 布局中使用自定义 View,并设置属性值。 ```xml <com.example.MyCustomView android:layout_width="match_parent" android:layout_height="wrap_content" app:customAttr1="123" app:customAttr2="hello" app:customAttr3="true" /> ``` 在上面的代码中,`app:customAttr1`、`app:customAttr2`、`app:customAttr3` 是在 attrs.xml 文件中定义的自定义属性名,可以在 XML 布局中使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值