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都會被調用。此時界面已渲染結束
   @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裏常用方法及座標相關的概念,也是爲後期的內容做鋪墊。歡迎關注公衆號【龍旋】能獲取最新更新內容哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章