收集整理 View必須要了解的Android坐標知識


說來說去都不如 畫圖示意 簡單易懂啊!!!真是的! 來吧~~先上張圖~~!


(一)首先明確一下 android 中的坐標系統 :

     屏幕的左上角是坐標系統原點(0,0)      原點向右延伸是X軸正方向,原點向下延伸是Y軸正方向   (二)關於Scroll: 屏幕顯示的內容很多時,會有超出一屏的情況,於是就產生了Scroll的概念。         在View類中有個方法:       getScrollY()  英文原文描述是:       Return the scrolled top position of this view. This is the top edge of the displayed part of your view....       其實理解起來仍然就是:就是這個view相對於“坐標系統原點”(見上圖)在Y軸上的偏移量.(getScrollX同理)      【哇哈,有了圖就是好說明啊~ 省了多少語言描述啊,而且還不一定能說清楚~】
      getScrollY()就是當前視圖相對於屏幕原點在Y軸上的偏移量.

(三)MotionEvent類中 getRowX()和 getX()的區別:

      event.getRowX():觸摸點相對於屏幕原點的x坐標
      event.getX():   觸摸點相對於其所在組件原點的x坐標

     於是乎: view.getScrollY() + event.getY() 就得到了view中的觸摸點在Y軸上的偏移量


結論:
當你觸到按鈕時,x,y是相對於該按鈕左上點(控件本身)的相對位置。
而rawx,rawy始終是相對於屏幕的位置。





可知:

getRowX:觸摸點相對於屏幕的坐標
getX: 觸摸點相對於按鈕的坐標
getTop: 按鈕左上角相對於父view(LinerLayout)的y坐標
getLeft: 按鈕左上角相對於父view(LinerLayout)的x坐標

可以想象 getRight()等同於下面的計算:getLeft()+getWidth()。

getX()是表示Widget相對於自身左上角的x坐標,而getRawX()是表示相對於屏幕左上角的x坐標值(注意:這個屏幕左上角是手機屏幕左上角,不管activity是否有titleBar或是否全屏幕),getY(),getRawY()一樣的道理


(四)TextView類中

       有個 getLayout()方法:the Layout that is currently being used to display the text. This

                               can be null if the text or width has recently changes.

       其返回類型是Layout ,也就是返回textView的布局。

 

       然后重要的是通過這個 layout調用一個方法:

       getLineForVertical(int verticalPointPosition)  //得到某點在垂直方向上的行數值

 

       於是綜上所述,在實際的觸摸事件中可以這樣使用:

       Layout layout=textView.getLayout();

       int line = layout.getLineForVertical(textView.getScrollY() + (int) event.getY());

       //得到觸摸點在textView中垂直方向上的行數值。參數是觸摸點在Y軸上的偏移量

 

      接下來繼續介紹一個方法,要用到上邊的 layout 和 line:

      layout.getOffsetForHorizontal( line ,  (int) event.getX() );

      //得到觸摸點在某一行水平方向上的偏移量。

        參數分別是: 該行行數值 和 觸摸點在該行X軸上的偏移量。

        此方法得到的該值會根據該行上的文字的多少而變化,並不是橫向上的像素大小; 






整個坐標系是以手機屏幕左上角為原點(0,0),如果在屏幕沒有滑動之前,這一理解肯定是ok的,但在滑屏之后,就會產生很多歧義和混淆,原因在於使用過程當中,很多方法的參數並非是參照屏幕,而是相對於父視圖,對這整個過程和后面自定義控件的坐標變化帶來的各個參數變化來說理解起來就並不那么適合了,最開始給人的感覺是越來越不清楚這個坐標該怎么設置,好像坐標系總在發生變化,后來才慢慢在思維當中構建起視圖與視圖容器以及屏幕之間的關系。

android.view.View.layout(int l, int t, int r, int b)    layout的過程就是確定View在屏幕上顯示的具體位置,在代碼中就是設置其成員變量mLeft,mTop,mRight,mBottom的值,這幾個值構成的矩形區域就是該View顯示的位置,不過這里的具體位置都是相對與父視圖的位置mLeft代表當前view.layout的這個view的左邊緣離它的父視圖左邊緣的距離,拿上面“子視圖2.layout(int l, int t, int r, int b) ”來說,它的父視圖便是子視圖1,2,3合起來形成的整個大矩形,那么這里將父視圖的左上角定為(0,0),那么可以確定mLeft為一個子視圖寬度320,以此類推,mTop指當前view的上邊緣離父視圖上邊緣的距離。而以此為界,mRight所指的是當前view的右邊緣離父視圖左邊緣的距離,一眼可以看出值為640(mLeft+自己的寬度),mBottom也是指當前view的下邊緣離父視圖的上邊緣的距離。至於為何如此,大概是因為坐標系的緣故,坐標中的任何點都必須以(0,0)為起點,XY軸為衡量。

視圖左側位置  view.getLeft() 
視圖右側位置 view.getRight()

視圖頂部位置 view.getTop();
視圖底部位置 view.getBottom();
這四個方法所獲取到的各個左上右下的值與layout的四個參數代表的是一樣的,都是相對父視圖的左邊緣與上邊緣。

視圖寬度 view.getWidth();
視圖高度 view.getHeight() ;
這兩個方法獲取的是該view的高和寬,僅僅在滑動的情況下,或者說該view的大小如果不發生變化,它的值是不會變的。
getMeasuredWidth();
getMeasuredHeight();
說到這里就不得不提getWidth()、getHeight()和getMeasuredWidth()、getMeasuredHeight()這兩對函數之間的區別,getMeasuredWidth()、getMeasuredHeight()返回的是measure過程得到的mMeasuredWidth和mMeasuredHeight的值,而getWidth()和getHeight()返回的是mRight - mLeft和mBottom - mTop的值。一般情況下layout過程會參考measure過程中計算得到的mMeasuredWidth和mMeasuredHeight來安排子視圖在父視圖中顯示的位置,但這不是必須的,measure過程得到的結果可能完全沒有實際用處,特別是對於一些自定義的ViewGroup,其子視圖的個數、位置和大小都是固定的,這時候我們可以忽略整個measure過程,只在layout函數中傳入的4個參數來安排每個子視圖的具體位置。

view.getX();
view.getY();
getX和getY獲取到的值為相對於父視圖而言的兩個左邊緣和上邊緣的距離。

view.getLocationOnScreen(location);  該方法可以獲取到當前view與屏幕的關系,location(0)代表X值,表示該view的左邊緣與屏幕的左邊緣之間的距離。可以想象,當滑屏產生,view開始移動該值肯定會改變的。location(1)代表Y值,表示該view的上邊緣與屏幕的上邊緣之間的距離,該距離肯定是包含標題欄的高度的。
getLocationInWindow();  

ps:View.getLocationInWindow()和 View.getLocationOnScreen()在window占據全部screen時,返回值相同,不同的典型情況是在Dialog中時。當Dialog出現在屏幕中間時,View.getLocationOnScreen()取得的值要比View.getLocationInWindow()取得的值要大。

VelocityTracker.getXVelocity() 指滑動速度包括速率和方向兩個方面,往左滑動小於0,值為負;往右滑動大於0,值為正。

getLocationInWindow 和 getLocationOnScreen

int[] location = new  int[2] ;
view.getLocationInWindow(location); //獲取在當前窗口內的絕對坐標
view.getLocationOnScreen(location);//獲取在整個屏幕內的絕對坐標
location [0]--->x坐標,location [1]--->y坐標
getLocationOnScreen

,計算該視圖在全局坐標系中的x,y值,(注意這個值是要從屏幕頂端算起,也就是索包括了通知欄的高度)//獲取在當前屏幕內的絕對坐標
getLocationInWindow ,計算該視圖在它所在的widnow的坐標x,y值,//獲取在整個窗口內的絕對坐標
getLeft getTopgetBottom,getRight這一組是獲取相對在它父親里的坐標


view.scrollTo(x,y)  將整個父視圖的左上角定為(0,0),再移動這個屏幕的左上角到父視圖的點(x,y)處,注意此處的x和y是根據父視圖的坐標系來定的。
view.scrollBy(x,y)  x代表橫向移動的距離,y代表縱向移動的距離

view.getScrollX
view.getScrollY
將整個父視圖的左上角定為(0,0),那么子view.getScrollX會獲取到屏幕左邊緣減去父視圖的左邊緣為0的距離,特別當滑屏時,父視圖會被迫隱藏一部分,因為屏幕的大小是固定的。getScrollY以此類推。

event.getX()
event.getY()
該方法是不受視圖影響的,X和Y的值僅僅代表手指在以左上角(0,0)為原點的屏幕觸摸點的坐標值。

Scroller.getCurrY()
Scroller.getCurrX()
該方法拿橫軸來說,代表屏幕的左邊緣離父視圖的左邊緣的距離。

Scroller.startScroll(int startX, int startY, int dx, int dy
四個參數分別表示起點的坐標和滑動的向量,即從(startX,startY)開始滑動,橫向滑動dx的距離,縱向滑動dy的距離(正值向左滑,負值向右滑),而這里的startX,startY又是參照的父視圖左上角為原點坐標的坐標系,滑屏時經常使用getScrollX()和getScrollY()來代表屏幕左邊緣和上邊緣處於父視圖坐標系的具體位置

TranslateAnimation()
參數參照:http://blog.sina.com.cn/s/blog_90b91bf10101ai3e.html


以上是在做滑屏控件經常用到的方法,一方面需要了解layout和measure的基本流程,更重要一方面,當你想要實現某一個效果的時候,比如slidingmenu那樣的控件,查看源碼我們可以知道它是繼承的ViewGroup,該怎樣入手去做呢。

首先,需要了解它的父視圖是什么,slidingmenu為例,打開程序,第一眼,是一個很普通的視圖頁面,當向右滑動手指,這個視圖頁面開始向右邊移動,而從左邊會慢慢移出來另一部分視圖,看上去像是抽出來的或者是隱藏的,事實上拋開陰影效果來講,想象手機屏幕的左邊有一部分我們看不到的視圖,它就是這個被抽出來的menu視圖了。概括來說,一個主view,一個menu其實是並排於一個大視圖上面的。
找到了父視圖,接下來就好辦了,認定這個父視圖的寬度就是主view的寬度和menu的寬度之和(暫不考慮padding之類),高度就是屏幕的高度,那么在思維當中這個二維平面就產生了,將它想成一張紙,然后對准主view將這張紙貼到手機屏幕上,左右滑動,會看到其實slidingmenu也就是這么個效果。

然后,實現的思路會清晰很多。定義這個父視圖為myview繼承viewgroup,原因在於盡管主view和menu並排在一個大view下,但畢竟兩者的內容不同,后面需要放進不同的控件處理不同的事件,這個父視圖內包含着兩個view,到時候處理起來會方便很多,setcontentview為這個父視圖,那么打開程序的第一眼就會看到它。再定義這兩個view設置好兩個內容布局,並將它們addview添加到myview當中。外部工作基本就完成了,可以呈現父視圖,並且父視圖內有兩個子view。

接下來,需要去完善一些細節,父視圖內的子view該如何放置,這是關乎成敗的一環,也就是如何將這張紙貼到我們希望的位置,這時就是onlayout的處理了,處理好屏幕,父視圖子view之間的位置關系,通過各自的layout參數設置來擺放妥當各個view,比如開始的時候menu是隱藏的,這個就是通過位置的擺放設置的,然后它是從左邊滑出來的,說明它處於父視圖的左邊位置,而主view處於相對右邊的位置,而屏幕剛好也處於父視圖右邊的位置,恰好能看到主view的全貌,在腦海里如果能有清晰的畫面出現,實現起來就會輕松很多。當實現了這個擺放,就可以理解menudrawer里面上下左右都可以滑出menu的結構了。

最后,便是滑動效果,請相信這樣的控件里面,任何處理肯定都會和view位置的擺放扯上關系,滑動方向,滑動距離等等都涉及到坐標的處理。這也是為何上面列出那些常用的獲取view坐標的方法。

總結下來,構建類似這樣的控件,也就這三點,明確父子視圖和屏幕的關系,通過坐標和位置參數設置它們的關系,處理這些關系發生變化的情況。


當然,事實上slidingmenu遠遠沒這么簡單,其中為了方便后續開發,它內置了很多接口和處理,大多數都是位置坐標和事件監聽相關聯,而萬變不離其宗的是,它也肯定有這三個方面的構建,理解了這些基本的東西,嘗試做一些自己想象的效果,對自定義的理解來說,進步會非常大。




資料來自互聯網


Android~獲取view在屏幕中的位置

getLocalVisibleRect , 返回一個填充的Rect對象, 感覺是這個View的Rect大小,left,top取到的都是0

getGlobalVisibleRect , 獲取全局坐標系的一個視圖區域, 返回一個填充的Rect對象;該Rect是基於總整個屏幕的

getLocationOnScreen ,計算該視圖在全局坐標系中的x,y值,(注意這個值是要從屏幕頂端算起,也就是索包括了通知欄的高度)//獲取在當前屏幕內的絕對坐標 

getLocationInWindow ,計算該視圖在它所在的widnow的坐標x,y值,//獲取在整個窗口內的絕對坐標 (不是很理解= =、)

getLeft , getTopgetBottomgetRight,  這一組是獲取相對在它父親里的坐標

**注**:如果在Activity的OnCreate()事件輸出那些參數,是全為0,要等UI控件都加載完了才能獲取到這些

example:

    int[] location = new int[2];
    v.getLocationOnScreen(location);
    int x = location[0];
    int y = location[1];


Rect 與 RectF

Rect 這個類到底是干嘛用的,看源碼介紹

/**
* Rect holds four integer coordinates for a rectangle. The rectangle is
* represented by the coordinates of its 4 edges (left, top, right bottom).
* These fields can be accessed directly. Use width() and height() to retrieve
* the rectangle's width and height. Note: most methods do not check to see that
* the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
*/
public final class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;

private static final Pattern FLATTENED_PATTERN = Pattern.compile(
"(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)");

/**
* Create a new empty Rect. All coordinates are initialized to 0.
*/
public Rect() {}

/**
* Create a new rectangle with the specified coordinates. Note: no range
* checking is performed, so the caller must ensure that left <= right and
* top <= bottom.
*
* @param left The X coordinate of the left side of the rectagle
* @param top The Y coordinate of the top of the rectangle
* @param right The X coordinate of the right side of the rectagle
* @param bottom The Y coordinate of the bottom of the rectangle
*/
public Rect(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}

   /**
     * @return the rectangle's width. This does not check for a valid rectangle
     * (i.e. left <= right) so the result may be negative.
     */
    public final int width() {
        return right - left;
    }

    /**
     * @return the rectangle's height. This does not check for a valid rectangle
     * (i.e. top <= bottom) so the result may be negative.
     */
    public final int height() {
        return bottom - top;
    }
    
    /**
     * @return the horizontal center of the rectangle. If the computed value
     *         is fractional, this method returns the largest integer that is
     *         less than the computed value.
     */
    public final int centerX() {
        return (left + right) >> 1;
    }
    
    /**
     * @return the vertical center of the rectangle. If the computed value
     *         is fractional, this method returns the largest integer that is
     *         less than the computed value.
     */
    public final int centerY() {
        return (top + bottom) >> 1;
    }
    
    /**
     * @return the exact horizontal center of the rectangle as a float.
     */
    public final float exactCenterX() {
        return (left + right) * 0.5f;
    }
    
    /**
     * @return the exact vertical center of the rectangle as a float.
     */
    public final float exactCenterY() {
        return (top + bottom) * 0.5f;
    }
看到了,這個類其實就是一個矩形,它里面記錄了左上右下4個點的坐標位置。幾個比較常用的方法,其實自己理解了也可以寫,但是API既然已經提供了,就不要再重復制造輪子了,但是計算中心位置的方法效率很高,可以借鑒。

得到寬度,因為沒有做 左點<=右點 所以結果可能為負值

 /**
* @return the rectangle's width. This does not check for a valid rectangle
* (i.e. left <= right) so the result may be negative.
*/
public final int width() {
return right - left;
}

得到高度,同上

 /**
* @return the rectangle's height. This does not check for a valid rectangle
* (i.e. top <= bottom) so the result may be negative.
*/
public final int height() {
return bottom - top;
}

得到整數的中心點x,y坐標

 /**
* @return the horizontal center of the rectangle. If the computed value
* is fractional, this method returns the largest integer that is
* less than the computed value.
*/
public final int centerX() {
return (left + right) >> 1;
}

/**
* @return the vertical center of the rectangle. If the computed value
* is fractional, this method returns the largest integer that is
* less than the computed value.
*/
public final int centerY() {
return (top + bottom) >> 1;
}

得到精確的值float 中心點x,y

/**
* @return the exact horizontal center of the rectangle as a float.
*/
public final float exactCenterX() {
return (left + right) * 0.5f;
}

/**
* @return the exact vertical center of the rectangle as a float.
*/
public final float exactCenterY() {
return (top + bottom) * 0.5f;
}

RectF 看源碼其實就是提高了精度的,其他區別不大

常用的計算方法,比如獲得TextView文本內容的矩形大小,其實TextView就是個矩形,里面填充了文字。我們有個邏輯是給這個textview外面套一個單線條紅色圈,就需要知道它的Rect值

 mTextPaint = new Paint();
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);

這樣mTextBounds就是Rect類的Object


MeasureSpec學習


在自定義ViewViewGroup的時候,我們經常會遇到int型的MeasureSpec來表示一個組件的大小,這個變量里面不僅有組件的尺寸大小,還有大小的模式。

這個大小的模式,有點難以理解。在系統中組件的大小模式有三種:

1.精確模式(MeasureSpec.EXACTLY

在這種模式下,尺寸的值是多少,那么這個組件的長或寬就是多少。

2.最大模式(MeasureSpec.AT_MOST

這個也就是父組件,能夠給出的最大的空間,當前組件的長或寬最大只能為這么大,當然也可以比這個小。

3.未指定模式(MeasureSpec.UNSPECIFIED

這個就是說,當前組件,可以隨便用空間,不受限制。

    可能有很多人想不通,一個int型整數怎么可以表示兩個東西(大小模式和大小的值),一個int類型我們知道有32位。而模式有三種,要表示三種狀  態,至少得2位二進制位。於是系統采用了最高的2位表示模式。如圖:

最高兩位是00的時候表示"未指定模式"。即MeasureSpec.UNSPECIFIED

最高兩位是01的時候表示"'精確模式"。即MeasureSpec.EXACTLY

最高兩位是11的時候表示"最大模式"。即MeasureSpec.AT_MOST

很多人一遇到位操作頭就大了,為了操作簡便,於是系統給我提供了一個MeasureSpec工具類。

這個工具類有四個方法和三個常量(上面所示)供我們使用:

 

//這個是由我們給出的尺寸大小和模式生成一個包含這兩個信息的int變量,這里這個模式這個參數,傳三個常量中的一個。

public static int makeMeasureSpec(int size, int mode)

 

//這個是得到這個變量中表示的模式信息,將得到的值與三個常量進行比較。

public static int getMode(int measureSpec)

 

//這個是得到這個變量中表示的尺寸大小的值。

public static int getSize(int measureSpec)

 

//把這個變量里面的模式和大小組成字符串返回來,方便打日志

 public static String toString(int measureSpec)

 

 

 

MeasureSpec.EXACTLY:當我們將控件的layout_width或layout_height指定為具體數值時如andorid:layout_width="50dip",或者為FILL_PARENT是,都是控件大小已經確定的情況,都是精確尺寸,注意FILL_PARENT是屏幕的尺寸,所以是精確值。

        MeasureSpec.AT_MOST是最大尺寸,當控件的layout_width或layout_height指定為WRAP_CONTENT時,控件大小一般隨着控件的子空間或內容進行變化,此時控件尺寸只要不超過父控件允許的最大尺寸即可。因此,此時的mode是AT_MOST,size給出了父控件允許的最大尺寸。

        MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,通過measure方法傳入的模式

因此,在重寫onMeasure方法時要根據模式不同進行尺寸計算。下面代碼就是一種比較典型的方式:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. @Override      
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {      
  3.     setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false));      
  4. }      
  5.       
  6.       
  7. private int getMeasuredLength(int length, boolean isWidth) {      
  8.     int specMode = MeasureSpec.getMode(length);      
  9.     int specSize = MeasureSpec.getSize(length);      
  10.     int size;      
  11.     int padding = isWidth ? getPaddingLeft() + getPaddingRight()      
  12.             : getPaddingTop() + getPaddingBottom();      
  13.     if (specMode == MeasureSpec.EXACTLY) {      
  14.         size = specSize;      
  15.     } else {      
  16.         size = isWidth ? padding + mWave.length / 4 : DEFAULT_HEIGHT      
  17.                 + padding;      
  18.         if (specMode == MeasureSpec.AT_MOST) {      
  19.             size = Math.min(size, specSize);      
  20.         }      
  21.     }      
  22.     return size;      
  23. }    

 

 

解決ScrollView嵌套ListView和GridView沖突的方法

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class MyListView extends ListView {  
  2.         public MyListView(Context context) {  
  3.                 super(context);  
  4.         }  
  5.         public MyListView(Context context, AttributeSet attrs) {  
  6.                 super(context, attrs);  
  7.         }  
  8.         public MyListView(Context context, AttributeSet attrs, int defStyle) {  
  9.                 super(context, attrs, defStyle);  
  10.         }  
  11.         @Override  
  12.         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  13.                 int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  
  14.                                 MeasureSpec.AT_MOST);  
  15.                 super.onMeasure(widthMeasureSpec, expandSpec);  
  16.         }  
  17. }  
  18.   
  19.   
  20.    
  21. public class MyGridView extends GridView {     
  22.     private boolean haveScrollbar = true;     
  23.     public MyGridView(Context context) {     
  24.         super(context);     
  25.     }     
  26.     public MyGridView(Context context, AttributeSet attrs) {     
  27.         super(context, attrs);     
  28.     }     
  29.     public MyGridView(Context context, AttributeSet attrs, int defStyle) {     
  30.         super(context, attrs, defStyle);     
  31.     }     
  32.     /**    
  33.      * 設置是否有ScrollBar,當要在ScollView中顯示時,應當設置為false。 默認為 true    
  34.      *     
  35.      * @param haveScrollbars    
  36.      */     
  37.     public void setHaveScrollbar(boolean haveScrollbar) {     
  38.         this.haveScrollbar = haveScrollbar;     
  39.     }     
  40.     @Override     
  41.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {     
  42.         if (haveScrollbars == false) {     
  43.             int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);    
  44.             super.onMeasure(widthMeasureSpec, expandSpec);     
  45.         } else {     
  46.             super.onMeasure(widthMeasureSpec, heightMeasureSpec);     
  47.         }     
  48.     }     

在自定義ViewViewGroup的時候,我們經常會遇到int型的 MeasureSpec 來表示一個組件的大小,這個變量里面不僅有組件的尺寸大小,還有大小的模式。

這個大小的模式,有點難以理解。在系統中組件的大小模式有三種:

1.精確模式(MeasureSpec.EXACTLY

在這種模式下,尺寸的值是多少,那么這個組件的長或寬就是多少。

2.最大模式(MeasureSpec.AT_MOST

這個也就是父組件,能夠給出的最大的空間,當前組件的長或寬最大只能為這么大,當然也可以比這個小。

3.未指定模式(MeasureSpec.UNSPECIFIED

這個就是說,當前組件,可以隨便用空間,不受限制。

    可能有很多人想不通,一個int型整數怎么可以表示兩個東西(大小模式和大小的值),一個int類型我們知道有32位。而模式有三種,要表示三種狀  態,至少得2位二進制位。於是系統采用了最高的2位表示模式。如圖:

最高兩位是00的時候表示"未指定模式"。即MeasureSpec.UNSPECIFIED

最高兩位是01的時候表示"'精確模式"。即MeasureSpec.EXACTLY

最高兩位是11的時候表示"最大模式"。即MeasureSpec.AT_MOST

很多人一遇到位操作頭就大了,為了操作簡便,於是系統給我提供了一個MeasureSpec工具類。

這個工具類有四個方法和三個常量(上面所示)供我們使用:

 

//這個是由我們給出的尺寸大小和模式生成一個包含這兩個信息的int變量,這里這個模式這個參數,傳三個常量中的一個。

public static int makeMeasureSpec(int size, int mode)

 

//這個是得到這個變量中表示的模式信息,將得到的值與三個常量進行比較。

public static int getMode(int measureSpec)

 

//這個是得到這個變量中表示的尺寸大小的值。

public static int getSize(int measureSpec)

 

//把這個變量里面的模式和大小組成字符串返回來,方便打日志

 public static String toString(int measureSpec)

 

 

 

MeasureSpec.EXACTLY:當我們將控件的layout_width或layout_height指定為具體數值時如andorid:layout_width="50dip",或者為FILL_PARENT是,都是控件大小已經確定的情況,都是精確尺寸。

        MeasureSpec.AT_MOST是最大尺寸,當控件的layout_width或layout_height指定為WRAP_CONTENT時,控件大小一般隨着控件的子空間或內容進行變化,此時控件尺寸只要不超過父控件允許的最大尺寸即可。因此,此時的mode是AT_MOST,size給出了父控件允許的最大尺寸。

        MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,通過measure方法傳入的模式。

因此,在重寫onMeasure方法時要根據模式不同進行尺寸計算。下面代碼就是一種比較典型的方式:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. @Override      
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {      
  3.     setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false));      
  4. }      
  5.       
  6.       
  7. private int getMeasuredLength(int length, boolean isWidth) {      
  8.     int specMode = MeasureSpec.getMode(length);      
  9.     int specSize = MeasureSpec.getSize(length);      
  10.     int size;      
  11.     int padding = isWidth ? getPaddingLeft() + getPaddingRight()      
  12.             : getPaddingTop() + getPaddingBottom();      
  13.     if (specMode == MeasureSpec.EXACTLY) {      
  14.         size = specSize;      
  15.     } else {      
  16.         size = isWidth ? padding + mWave.length / 4 : DEFAULT_HEIGHT      
  17.                 + padding;      
  18.         if (specMode == MeasureSpec.AT_MOST) {      
  19.             size = Math.min(size, specSize);      
  20.         }      
  21.     }      
  22.     return size;      
  23. }    

 

 

解決ScrollView嵌套ListView和GridView沖突的方法

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class MyListView extends ListView {  
  2.         public MyListView(Context context) {  
  3.                 super(context);  
  4.         }  
  5.         public MyListView(Context context, AttributeSet attrs) {  
  6.                 super(context, attrs);  
  7.         }  
  8.         public MyListView(Context context, AttributeSet attrs, int defStyle) {  
  9.                 super(context, attrs, defStyle);  
  10.         }  
  11.         @Override  
  12.         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  13.                 int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  
  14.                                 MeasureSpec.AT_MOST);  
  15.                 super.onMeasure(widthMeasureSpec, expandSpec);  
  16.         }  
  17. }  
  18.   
  19.   
  20.    
  21. public class MyGridView extends GridView {     
  22.     private boolean haveScrollbar = true;     
  23.     public MyGridView(Context context) {     
  24.         super(context);     
  25.     }     
  26.     public MyGridView(Context context, AttributeSet attrs) {     
  27.         super(context, attrs);     
  28.     }     
  29.     public MyGridView(Context context, AttributeSet attrs, int defStyle) {     
  30.         super(context, attrs, defStyle);     
  31.     }     
  32.     /**    
  33.      * 設置是否有ScrollBar,當要在ScollView中顯示時,應當設置為false。 默認為 true    
  34.      *     
  35.      * @param haveScrollbars    
  36.      */     
  37.     public void setHaveScrollbar(boolean haveScrollbar) {     
  38.         this.haveScrollbar = haveScrollbar;     
  39.     }     
  40.     @Override     
  41.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {     
  42.         if (haveScrollbars == false) {     
  43.             int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);    
  44.             super.onMeasure(widthMeasureSpec, expandSpec);     
  45.         } else {     
  46.             super.onMeasure(widthMeasureSpec, heightMeasureSpec);     
  47.         }     
  48.     }     

Paint方法解析

  1. /**    
  2.   
  3.   
  4.      * Paint即畫筆,在繪圖過程中起到了極其重要的作用,畫筆主要保存了顏色,    
  5.   
  6.      * 樣式等繪制信息,指定了如何繪制文本和圖形,畫筆對象有很多設置方法,    
  7.   
  8.      * 大體上可以分為兩類,一類與圖形繪制相關,一類與文本繪制相關。           
  9.   
  10.      *     
  11.   
  12.      * <strong><span style="color: #800000; font-size: small;">1.圖形繪制  </span></strong>  
  13.   
  14.      * setARGB(int a,int r,int g,int b);    
  15.   
  16.      * 設置繪制的顏色,a代表透明度,r,g,b代表顏色值。    
  17.   
  18.      *     
  19.   
  20.      * setAlpha(int a);    
  21.   
  22.      * 設置繪制圖形的透明度。    
  23.   
  24.      *     
  25.   
  26.      * setColor(int color);    
  27.   
  28.      * 設置繪制的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。    
  29.   
  30.      *     
  31.   
  32.     * setAntiAlias(boolean aa);    
  33.   
  34.      * 設置是否使用抗鋸齒功能,會消耗較大資源,繪制圖形速度會變慢。    
  35.   
  36.      *     
  37.   
  38.      * setDither(boolean dither);    
  39.   
  40.      * 設定是否使用圖像抖動處理,會使繪制出來的圖片顏色更加平滑和飽滿,圖像更加清晰    
  41.   
  42.      *     
  43.   
  44.      * setFilterBitmap(boolean filter);    
  45.   
  46.      * 如果該項設置為true,則圖像在動畫進行中會濾掉對Bitmap圖像的優化操作,加快顯示    
  47.   
  48.      * 速度,本設置項依賴於dither和xfermode的設置    
  49.   
  50.      *     
  51.   
  52.      * setMaskFilter(MaskFilter maskfilter);    
  53.   
  54.      * 設置MaskFilter,可以用不同的MaskFilter實現濾鏡的效果,如濾化,立體等       *     
  55.   
  56.      * setColorFilter(ColorFilter colorfilter);    
  57.   
  58.      * 設置顏色過濾器,可以在繪制顏色時實現不用顏色的變換效果    
  59.   
  60.      *     
  61.   
  62.      * setPathEffect(PathEffect effect);    
  63.   
  64.      * 設置繪制路徑的效果,如點畫線等    
  65.   
  66.      *     
  67.   
  68.      * setShader(Shader shader);    
  69.   
  70.      * 設置圖像效果,使用Shader可以繪制出各種漸變效果    
  71.   
  72.      *    
  73.   
  74.      * setShadowLayer(float radius ,float dx,float dy,int color);    
  75.   
  76.      * 在圖形下面設置陰影層,產生陰影效果,radius為陰影的角度,dx和dy為陰影在x軸和y軸上的距離,color為陰影的顏色    
  77.   
  78.      *     
  79.   
  80.      * setStyle(Paint.Style style);    
  81.   
  82.      * 設置畫筆的樣式,為FILL,FILL_OR_STROKE,或STROKE    
  83.   
  84.      *     
  85.   
  86.      * setStrokeCap(Paint.Cap cap);    
  87.   
  88.      * 當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的圖形樣式,如圓形樣式    
  89.   
  90.      * Cap.ROUND,或方形樣式Cap.SQUARE    
  91.   
  92.      *     
  93.   
  94.      * setSrokeJoin(Paint.Join join);    
  95.   
  96.      * 設置繪制時各圖形的結合方式,如平滑效果等    
  97.   
  98.      *     
  99.   
  100.      * setStrokeWidth(float width);    
  101.   
  102.      * 當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的粗細度    
  103.   
  104.      *     
  105.   
  106.      * setXfermode(Xfermode xfermode);    
  107.   
  108.      * 設置圖形重疊時的處理方式,如合並,取交集或並集,經常用來制作橡皮的擦除效果    
  109.   
  110.      *     
  111.   
  112.      *<span style="color: #800000; font-size: small;"><strong> 2.文本繪制  </strong></span>  
  113.   
  114.      * setFakeBoldText(boolean fakeBoldText);    
  115.   
  116.      * 模擬實現粗體文字,設置在小字體上效果會非常差    
  117.   
  118.      *     
  119.   
  120.      * setSubpixelText(boolean subpixelText);    
  121.   
  122.      * 設置該項為true,將有助於文本在LCD屏幕上的顯示效果    
  123.   
  124.      *     
  125.   
  126.      * setTextAlign(Paint.Align align);    
  127.   
  128.      * 設置繪制文字的對齊方向    
  129.   
  130.      *     
  131.   
  132.    * setTextScaleX(float scaleX);    
  133.   
  134.     * 設置繪制文字x軸的縮放比例,可以實現文字的拉伸的效果    
  135.   
  136.      *     
  137.   
  138.      * setTextSize(float textSize);    
  139.   
  140.      * 設置繪制文字的字號大小    
  141.   
  142.      *     
  143.   
  144.      * setTextSkewX(float skewX);    
  145.   
  146.      * 設置斜體文字,skewX為傾斜弧度    
  147.   
  148.      *     
  149.   
  150.      * setTypeface(Typeface typeface);    
  151.   
  152.      * 設置Typeface對象,即字體風格,包括粗體,斜體以及襯線體,非襯線體等    
  153.   
  154.      *     
  155.   
  156.      * setUnderlineText(boolean underlineText);    
  157.   
  158.      * 設置帶有下划線的文字效果    
  159.   
  160.      *     
  161.   
  162.      * setStrikeThruText(boolean strikeThruText);    
  163.   
  164.      * 設置帶有刪除線的效果    
  165.   
  166.      *     
  167.   
  168.      **/ 


AvoidXfermode學習  顏色容差器

Paint.setStrokeJoin(Join join)設置結合處的樣子,Miter:結合處為銳角, Round:結合處為圓弧:BEVEL:結合處為直線。
setStrokeMiter(float miter )是設置筆畫的傾斜度,如:小時候用的鉛筆,削的時候斜與垂直削出來的筆尖效果是

1.下面的Xfermode子類可以改變這種行為:

AvoidXfermode  指定了一個顏色和容差,強制Paint避免在它上面繪圖(或者只在它上面繪圖)。

PixelXorXfermode  當覆蓋已有的顏色時,應用一個簡單的像素XOR操作。

PorterDuffXfermode  這是一個非常強大的轉換模式,使用它,可以使用圖像合成的16條Porter-Duff規則的任意一條來控制Paint如何與已有的Canvas圖像進行交互。

要應用轉換模式,可以使用setXferMode方法,如下所示:

AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID);    borderPen.setXfermode(avoid);

 

2.Porter-Duff 效果圖:

 

 

1.PorterDuff.Mode.CLEAR

   所繪制不會提交到畫布上。
2.PorterDuff.Mode.SRC

   顯示上層繪制圖片
3.PorterDuff.Mode.DST

  顯示下層繪制圖片
4.PorterDuff.Mode.SRC_OVER

  正常繪制顯示,上下層繪制疊蓋。
5.PorterDuff.Mode.DST_OVER

  上下層都顯示。下層居上顯示。
6.PorterDuff.Mode.SRC_IN

   取兩層繪制交集。顯示上層。
7.PorterDuff.Mode.DST_IN

  取兩層繪制交集。顯示下層。
8.PorterDuff.Mode.SRC_OUT

 取上層繪制非交集部分。
9.PorterDuff.Mode.DST_OUT

 取下層繪制非交集部分。
10.PorterDuff.Mode.SRC_ATOP

 取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP

  取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR

  
13.PorterDuff.Mode.DARKEN


14.PorterDuff.Mode.LIGHTEN


15.PorterDuff.Mode.MULTIPLY


16.PorterDuff.Mode.SCREEN






注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com