• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 你真的了解View的坐標么?(轉載)

    View,對我們來說在熟悉不過了,從接觸Android開始,我們就一直在接觸View,界面當中到處都是 View,比如我們經常用到的TextView,Button,LinearLayout等等,但是我們真的了解View嗎?尤其是View的坐標。mLeft,mRight,mY,mX,mTranslationY,mScoollY,相對于屏幕的坐標等等這些概念你真的清楚了嗎?如果真的清楚了,那你沒有必要讀這篇博客,如果你還是有一些模糊,建議花上幾分鐘的時間讀一下。

    為什么要寫這一篇博客呢?

    因為掌握View的坐標很重要,尤其是對于自定義View,學習動畫有重大的意義。

    這篇博客主要講解一下問題

    • View 的 getLeft()和get Right()和 getTop() 和getBottom()
    • View 的 getY(), getTranslationY() 和 getTop() 之間的聯系
    • View 的 getScroolY 和 View 的 scrollTo() 和 scrollBy()
    • event.getY 和 event.getRawY()
    • 擴展,怎樣獲取狀態欄(StatusBar)和標題欄(titleBar)的高度

    基本概念

    簡單說明一下(上圖Activity采用默認Style,狀態欄和標題欄都會顯示):最大的草綠色區域是屏幕界面,紅色次大區域我們稱之為“應用界面區域”,最小紫色的區域我們稱之為“View繪制區域”;屏幕頂端、應用界面區之外的那部分顯示手機電池網絡運營商信息的為“狀態欄”,應用區域頂端、View繪制區外部顯示Activity名稱的部分我們稱為“標題欄”。

    從這張圖片我們可以看到 
    在Android中,當ActionBar存在的情況下,

    屏幕的 高度=狀態欄+應用區域的高度=狀態欄的 高度+(標題欄的 高度+View 繪制區域的高度)
    • 1
    • 1

    當ActionBar不存在的情況下

    屏幕的高度=狀態欄+應用區域的高度=狀態欄的 高度+(View 繪制區域的 高度)
    • 1
    • 1

    View 的 getLeft()和getRight()和 getTop() 和getBottom()

    View.getLeft() ;
    View.getTop() ;
    View.getBottom();
    View.getRight() ; 
    • 1
    • 2
    • 3
    • 4
    • 1
    • 2
    • 3
    • 4

    top是左上角縱坐標,left是左上角橫坐標,right是右下角橫坐標,bottom是右下角縱坐標,都是相對于它的直接父View而言的,而不是相對于屏幕而言的。這一點要區分清楚。那那個坐標是相對于屏幕而言的呢,以及要怎樣獲取相對于屏幕的坐標呢?

    目前View里面的變量還沒有一個是相對于屏幕而言的,但是我們可以獲取到相對于屏幕的坐標。一般來說,我們要獲取View的坐標和高度 等,都必須等到View繪制完畢以后才能獲取的到,在Activity 的 onCreate()方法 里面 是獲取不到的,必須 等到View繪制完畢以后才能獲取地到View的響應的坐標,一般來說,主要 有以下兩種方法。

    第一種方法,onWindowFocusChanged()方法里面進行調用

          @Override
        public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus); 
         //確保只會調用一次
          if(first){
            first=false;
            final int[] location = new int[2];     
            mView.getLocationOnScreen(location);
            int x1 = location[0]  ;
            int y1 = location[1]  ;
            Log.i(TAG, "onCreate: x1=" +x1);
            Log.i(TAG, "onCreate: y1=" +y1);
          }
       }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    第二種方法,在視圖樹繪制完成的時候進行測量

            mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
                    .OnGlobalLayoutListener() {
    
                @Override
                public void onGlobalLayout() {
                    //   移除監聽器,確保只會調用一次,否則在視圖樹發揮改變的時候又會調用
                    mView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    final int[] location = new int[2];
                    mView.getLocationOnScreen(location);
                    int x1 = location[0];
                    int y1 = location[1];
                    Log.i(TAG, "onCreate: x1=" + x1);
                    Log.i(TAG, "onCreate: y1=" + y1);
                }
            });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    View 的 getY(), getTranslationY() 和 getTop() 之間的聯

    getY()

    Added in API level 14 
    The visual y position of this view, in pixels.(返回的是View視覺上的圖標,即我們眼睛看到位置的Y坐標,默認值跟getTop()相同,別急,下面會解釋)

    getTranslationY()

    Added in API level 14 
    The vertical position of this view relative to its top position, in pixels.(豎直方向上相對于top的偏移量,默認值為0)

    那 getY() 和 getTranslationY() 和 getTop () 到底有什么關系呢?

    @ViewDebug.ExportedProperty(category = "drawing")
    public float getY() {
       return mTop + getTranslationY();
    }
    
        @ViewDebug.ExportedProperty(category = "drawing")
        public float getTranslationY() {
            return mRenderNode.getTranslationY();
        }
        @ViewDebug.CapturedViewProperty
        public final int getTop() {
            return mTop;
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    從以上的源碼我們可以知道 getY()= getTranslationY()+ getTop (),而 getTranslationY() 的默認值是0,除非我們通過 setTranlationY() 來改變它,這也就是我們上面上到的 getY 默認值跟 getTop()相同

    那我們要怎樣改變 top值 和 Y 值呢? 很明顯就是調用相應的set方法 ,即 setY() 和setTop() ,就可以改變他們 的值。

    View 的 getScroolY 和 View 的 scrollTo() 和 scrollBy()

    getScrollY是一個比較特別的函數,因為它涉及一個值叫mScrollY,簡單說,getScrollY一般得到的都是0,除非你調用過scrollTo或scrollBy這兩個函數來改變它。

    scrollTo() 和 scrollBy()

    從字面意思我們可以知道 scrollTo() 是滑動到哪里的意思 ,scrollBy()是相對當前的位置滑動了多少。當然這一點在源碼中也是可以體現出來的

    public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }
    public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    有幾點需要注意的是

    • 不論是scrollTo或scrollBy,其實都是對View的內容進行滾動而不是對View本身,你可以做個小實驗,一個LinearLayouy背景是黃色,里面放置一個子LinearLayout背景是藍色,調用scrollTo或scrollBy,移動的永遠是藍色的子LinearLayout。
    • 還有就是scrollTo和scrollBy函數的參數和坐標系是“相反的”,比如scrollTo(-100,0),View的內容是向X軸正方向移動的,這個相反打引號是因為并不是真正的相反,具體可以看源碼,關于這兩個函數的源碼分析大家可以看Android——源碼角度分析View的scrollBy()和scrollTo()的參數正負問題,一目了然。

    View 的 width 和 height

    @ViewDebug.ExportedProperty(category = "layout")
    public final int getHeight() {
        return mBottom - mTop;
    }
    • 1
    • 2
    • 3
    • 4
    • 1
    • 2
    • 3
    • 4

    我們可以看到 Android的 height 是由 mBottom 和 mTop 共同得出的,那我們要怎樣設置Android的高度呢?有人會說直接在xml里面設置 android:height=”” 不就OK了,那我們如果要動態設置height的高度呢,怎么辦?你可能會想到 setWidth()方法?但是我們找遍了View的所有方法,都沒有發現 setWidth()方法,那要怎樣動態設置height呢?其實有兩種方法

     int width=50;
    int height=100;
    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
    if(layoutParams==null){
        layoutParams=new ViewGroup.LayoutParams(width,height);
    }else{
        layoutParams.height=height;
    }
    view.setLayoutParams(layoutParams);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    第二種方法,單獨地改變top或者bottom的值,這種方法不推薦使用

    至于width,它跟height基本一樣,只不過它是有mRight 和mLeft 共同決定而已。

    需要注意的是,平時我們在執行動畫的過程,不推薦使用LayoutParams來改變View的狀態,因為改變LayoutParams會調用requestLayout()方法,會標記當前View及父容器,同時逐層向上提交,直到ViewRootImpl處理該事件,ViewRootImpl會調用三大流程,從measure開始,對于每一個含有標記位的view及其子View都會進行測量、布局、繪制,性能較差,源碼體現如下:關于requestLayout ()方法的更多分析可以查看這一篇博客Android View 深度分析requestLayout、invalidate與postInvalidate

    public void setLayoutParams(ViewGroup.LayoutParams params) {
        if (params == null) {
            throw new NullPointerException("Layout parameters cannot be null");
        }
        mLayoutParams = params;
        resolveLayoutParams();
        if (mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).onSetLayoutParams(this, params);
        }
        requestLayout();
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    因此我們如果在api 14 以后 ,在動畫執行過程中,要改變View的狀態,推薦使用setTranslationY()和setTranslationX(0等方法,而 盡量避免改變LayoutParams.因為性能嫌貴來說較差。

    event.getY() 和 event.getRawY()

    要區分于MotionEvent.getRawX() 和MotionEvent.getX();,

    在public boolean onTouch(View view, MotionEvent event) 中,當你觸到控件時,x,y是相對于該控件左上點(控件本身)的相對位置。 而rawx,rawy始終是相對于屏幕的位置。getX()是表示Widget相對于自身左上角的x坐標,而getRawX()是表示相對于屏幕左上角的x坐標值 (注意:這個屏幕左上角是手機屏幕左上角,不管activity是否有titleBar或是否全屏幕)。

    擴展,怎樣獲取狀態欄(StatusBar)和標題欄(titleBar)的高度

    
         public void onWindowFocusChanged(boolean hasFocus) {
            super.onWindowFocusChanged(hasFocus);
    
            //屏幕
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            Log.e(TAG, "屏幕高:" + dm.heightPixels);
    
            //應用區域
            Rect outRect1 = new Rect();
            getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1);
            //這個也就是狀態欄的 高度
            Log.e(TAG, "應用區頂部" + outRect1.top);
    
            Log.e(TAG, "應用區高" + outRect1.height());
    
            // 這個方法必須在有actionBar的情況下才能獲取到狀態欄的高度
            //View繪制區域
            Rect outRect2 = new Rect();
            getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect2);
            Log.e(TAG, "View繪制區域頂部-錯誤方法:" + outRect2.top);   //不能像上邊一樣由outRect2.top獲取,這種方式獲得的top是0,可能是bug吧
            Log.e(TAG, "View繪制區域高度:" + outRect2.height());
    
            int viewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();   //要用這種方法
            Log.e(TAG, "View繪制區域頂部-正確方法:" + viewTop);
    
            int titleBarHeight=viewTop;
    
            Log.d(TAG, "onWindowFocusChanged: 標題欄高度titleBarHeight=" +titleBarHeight);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    這里我們需要注意的 是在ActionBar存在的情況下,通過這種方法我們才能夠得出titleBar的高度,否則是無法得到的,因為viewTop 為0.


    版權聲明:本文為jungle_pig原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/jungle_pig/article/details/79769416

    智能推薦

    CSS權重,你真的懂了么

    1.什么是CSS權重? css權重決定了哪個css規則會起重要,當多個規則被應用于同一個元素時,權重高的將會起作用(權重高代表優先級高)。在日常開發過程中,大家多少都遇到過這樣的問題,寫不同的css樣式文件,結果產生相互覆蓋的問題。本文將詳細講述一下css權重規則,便于大家避坑。 2.CSS權重規則(級別由高到低) (1) !important 聲明級別最高,但同時也會被important級別覆蓋...

    你真的會寫 Markdown 么?

    1 文章簡介 本文使用 Markdown 進行排版,詳盡介紹了相關書寫規范,排版工具為 mdnice 需要注意的是,有部分編輯器自定義語法,并不完全通用所有平臺 2 通用語法 2.1 標題 在文字寫書寫不同數量的#可以完成不同的標題,如下: 一級標題 二級標題 三級標題 2.2 無序列表 無序列表的使用,在符號-后加空格使用。如下: 無序列表 1 無序列表 2 無序列表 3 如果要控制列表的層級,...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    猜你喜歡

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    精品国产乱码久久久久久蜜桃不卡