帶你真正認識View

笑葉林發表於2018-12-11

作為一個Android開發者,工作中肯定或多或少都會跟自定義View打交道,但是我們的第一反應就是這太難了,去網上找找,看看有沒有現成的可以拿來直接用的。

其實之所以我們覺得自定義View很難,根本原因還是我們對於View的基礎掌握不牢。

今天這篇文章,我就帶大家一起重新學習一下View的基礎。

View的建構函式

1.View(Context)

在Java程式碼裡面直接new的時候呼叫。

2. View(Context, AttributeSet)

.xml裡宣告的時候呼叫,AttributeSet是從.xml中解析出來的屬性集合。

<ImageView  
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/icon" />
複製程式碼

上面.xml中的layout_width, layout_height 以及src是從哪裡來的?它們可不是憑空產生的;實際上是通過<declare-styleable>把這些屬性明確的宣告為系統需要處理的東西。比如,src就是在這裡定義的:

<declare-styleable name="ImageView">  
    <!-- Sets a drawable as the content of this ImageView. -->
    <attr name="src" format="reference|color" />
</declare-styleable>
複製程式碼

每個declare-styleable產生一個R.styleable.[name],外加每個屬性的R.styleable.[name]_[attribute] 。比如,上面的程式碼產生 R.styleable.ImageViewR.styleable.ImageView_src

這些資源是什麼東西呢?R.styleable.[name]是所有屬性資源的陣列,系統使用它來查詢屬性值。每個R.styleable.[name]_[attribute]只不過是這個陣列的索引罷了,所以你可以一次性取出所有屬性,然後按索引分別查詢每個的值。

xml中屬性是以AttributeSet的形式通過構造方法傳遞給View的,但通常我們不直接使用AttributeSet。而是使用Theme.obtainStyledAttributes()。這是因為原始的屬性通常需要引用和應用樣式。比如,如果你在XML中定義了style=@style/MyStyle,這個方法先獲取MyStyle,然後把它的屬性混合進去。最終obtainStyledAttributes() 返回一個TypedArray,你可以用它來獲取屬性值。這個過程簡化之後就像這樣:

public ImageView(Context context, AttributeSet attrs) {
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ImageView, 0, 0);
    Drawable src = ta.getDrawable(R.styleable.ImageView_src);
    setImageDrawable(src);
    ta.recycle();
}
複製程式碼

這裡我們向obtainStyledAttributes()傳遞了兩個引數。第一個引數是AttributeSet attrs,即xml中的屬性;第二個引數是R.styleable.ImageView陣列,它告訴這個方法我們想取哪個屬性的值,這裡表示要獲取ImageView屬性的值;第三和第四個引數是兩個資源引用defStyleAttrdefStyleRes,將在第三和第四個構造方法中進行說明。 當獲得了TypedArray之後,我們就可以獲取單個屬性了。我們需要使用R.styleable.ImageView_src來正確索引陣列中的src屬性。

3. View(Context, AttributeSet, defStyleAttr)

defStyleAttr引數:預設的Style,指它在當前ApplicationActivity所用的Theme中的預設Style,為某個型別的View定義這個類的基礎樣式,如果我們不在構造方法傳入指定我們自定義的樣式則將使用Android系統預設的控制元件樣式,指定時需要間接的通過theme,如下所示:

1、在Theme(styles.xml)中設定樣式

<resources>  
    <style name="Theme">
      <item name="mStyle">@style/CustomStyle</item>
    </style>
    
    <!--具體樣式-->
    <style name="CustomStyle" >
      <item name="android:background">@android:color/black</item>
    </style>
</resource>
複製程式碼

2、在構造方法中使用

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.view, R.attr.mStyle, 0);
複製程式碼

4. View(Context, AttributeSet, defStyleAttr, defStyleRes)

defStyleRes引數:它只是一個用於指定樣式的style資源(@style/Widget.TextView)。比defStyleAttr簡單,不需要間接的通過theme。在API 21新增的。因此除非你的minSdkVersion21,否則不要使用它。

它們是串聯的,如果你呼叫了一個,所有的都會通過super被呼叫。串聯還意味著你只需重寫你需要的建構函式。一般來說,你只需實現前兩個(一個用於程式碼,一個用於XML inflation)。

View檢視結構

對於多View的檢視,結構是樹形結構:最頂層是ViewGroupViewGroup下可能有多個ViewGroupView,如下圖:

帶你真正認識View

注意:無論是measure過程、layout過程還是draw過程,永遠都是從View樹的根節點開始測量或計算(即從樹的頂端開始),一層一層、一個分支一個分支地進行(即樹形遞迴),最終計算整個View樹中各個View,最終確定整個View樹的相關屬性。

Android座標系

Android的座標系定義為:

  • 螢幕的左上角為座標原點
  • 向右為x軸增大方向
  • 向下為y軸增大方向

具體如下圖:

帶你真正認識View

View位置(座標)描述 )

  • View的位置由4個頂點決定的(如下圖A、B、C、D)
  • 4個頂點的位置描述分別由4個值決定(View的位置是相對於父控制元件而言的):

Top:子View上邊界到父view上邊界的距離
Left:子View左邊界到父view左邊界的距離
Bottom:子View下邊距到父View上邊界的距離
Right:子View右邊界到父view左邊界的距離

帶你真正認識View

View位置獲取方式

View的位置是通過view.getxxx()函式進行獲取(以Top為例):

// 獲取Top位置
public final int getTop() { 
  return mTop; 
} 
// 其餘如下:
getLeft();//獲取子View左上角距父View左側的距離 
getBottom(); //獲取子View右下角距父View頂部的距離
getRight(); //獲取子View右下角距父View左側的距離
複製程式碼

MotionEventget...()getRaw...()的區別

//get() :觸控點相對於其所在元件座標系的座標
event.getX();       
event.getY();
//getRaw() :觸控點相對於螢幕座標系的座標
event.getRawX();    
event.getRawY();
複製程式碼

具體如下圖:

帶你真正認識View

Android的角度(angle)與弧度(radian)

角度和弧度都是描述角的一種度量單位,區別如下圖:

帶你真正認識View

在預設的螢幕座標系中角度增大方向為順時針,與數學座標系中角度增大方向剛好相反。

帶你真正認識View

Android中顏色相關內容

Android支援的顏色模式:

帶你真正認識View

以ARGB8888為例介紹顏色定義:

帶你真正認識View

定義顏色的方式

  • 在java中定義顏色
//java中使用Color類定義顏色
int color = Color.GRAY; //灰色
//Color類中使用ARGB值表示顏色
int color = Color.argb(127, 255, 0, 0); //半透明紅色
//使用十六進位制定義顏色
int color = 0xaaff0000; //帶有透明度的紅色 
//Android中Color工具類 parseColor解析顏色字串
int color = Color.parseColor("#FFFFFF")//白色
複製程式碼
  • 在xml檔案中定義顏色 /res/values/color.xml
<?xml version="1.0" encoding="utf-8"?> 
<resources>
   //定義了紅色(沒有alpha(透明)通道) 
   <color name="red">#ff0000</color>
   //定義了藍色(沒有alpha(透明)通道) 
   <color name="green">#00ff00</color> 
</resources>
複製程式碼
  • xml檔案(不侷限與佈局xml檔案,其它xml檔案也可以用這種定義方式)中以"#"開頭定義顏色,後面跟十六進位制的值,有如下幾種定義方式:
#f00 //低精度 - 不帶透明通道紅色 == #ff0000
#af00 //低精度 - 帶透明通道紅色 == #aaff0000
#ff0000 //高精度 - 不帶透明通道紅色 
#aaff0000 //高精度 - 帶透明通道紅色
複製程式碼

引用顏色的方式

  • 在java檔案中引用color.xml中定義的顏色:
int color = getResources().getColor(R.color.mycolor);
複製程式碼
  • xml檔案(layoutstyle)中引用或者建立顏色:
<!--在style檔案中引用-->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> 
   <item name="colorPrimary">@color/red</item>
</style> 
<!--在layout檔案中引用在/res/values/color.xml中定義的顏色--> 
android:background="@color/red" 
<!--在layout檔案中建立並使用顏色--> 
android:background="#ff0000"
複製程式碼

希望這邊文章能對您有所幫助~~~~~~~~





原文連結

相關文章