美文网首页学习之鸿蒙&Android学习view
Android自定义控件坐标系解析

Android自定义控件坐标系解析

作者: 龙旋之谷 | 来源:发表于2021-05-18 11:48 被阅读0次

    自定义控件要想彻底的把握,掌握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都会被调用。此时界面已渲染结束
       @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();
            }
        });
    

    (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里常用方法及坐标相关的概念,也是为后期的内容做铺垫。欢迎关注公众号【龙旋】能获取最新更新内容哦。

    相关文章

      网友评论

        本文标题:Android自定义控件坐标系解析

        本文链接:https://www.haomeiwen.com/subject/edvejltx.html