Android 自定義View及其在佈局文件中的使用示例(二)

 

 轉載請註明出處
http://www.cnblogs.com/crashmaker/p/3530213.html
From crash_coder linguowu
linguowu0622@gamil.com

 

  前言:上一篇中(Android 自定義View及其在佈局文件中的使用示例)介紹了Android開發中,當系統提供的控件不知足開發者需求的時候,演示如何自定義View,本文將做爲上篇的延續,先大致上介紹Android是如何畫出界面的,屬於前提理論基礎,下一篇將重點介紹Android畫界面過程當中的幾個重要方法,如:

1,onMeasure()
2,onLayout()
3,onDraw()

Android繪圖的理論基礎:

1,咱們建立一個Activity來測試上一篇中自定義的View:

a)html

CustomViewActivity.javajava

1 public class CustomViewActivity extends Activity{
2 
3   @Override
4   protected void onCreate(Bundle savedInstanceState) {
5     // TODO Auto-generated method stub
6     super.onCreate(savedInstanceState);
7     setContentView(R.layout.customview_layout);
8   }
9 }

b)node

customview_layout.xmlandroid

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res/com.project.summary"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     android:background="@color/BgColor"
 7     android:orientation="vertical" >
 8 
 9     <com.project.summary.customview.CustomView
10         android:id="@+id/customView"
11         android:layout_width="wrap_content"
12         android:layout_height="wrap_content"
13         app:colorValue="@color/textRed"
14         app:textSize="20sp"
15         app:textString="This the Custom View1!!!" />
16 
17 </LinearLayout>

c)運行結果:app

2,Android是如何實現上圖的效果的呢?

a)ide

查看google文檔,它給出了以下解釋:佈局

When an Activity receives focus, it will be requested to draw its layout. The Android framework will handle the procedure for drawing, but the Activity must provide the root node of its layout hierarchy.

結合上面的例子來講明一下:當進入CustomViewActivity這個Activity時,該Activity得到焦點,此時,該Activity就會向系統請求繪製出它的佈局,這個請求經過Android framework來處理,前提是:CustomViewActivity必須提供該佈局的根結點,從CustomViewActivity.java看出,該Activity提供了R.layout.customview_layout,而該佈局的根結點就是咱們佈局文件的LinearLayout;測試

b)ui

   Drawing begins with the root node of the layout. It is requested to measure and draw the layout tree. Drawing is handled by walking the tree and rendering each View that intersects the invalid region. In turn, each ViewGroup is responsible for requesting each of its children to be drawn (with the draw() method) and each View is responsible for drawing itself. Because the tree is traversed in-order, this means that parents will be drawn before (i.e., behind) their children, with siblings drawn in the order they appear in the tree.

 從該段文檔能夠了解到,Android中View的繪製是從佈局的根結點開始,開始以前須要遍歷整個佈局結構,若是是ViewGroup,ViewGroup(如:LinearLayout,RelativeLayout等)須要對它的全部子View進行遍歷及繪製,若是隻是普通的View(TextView等),那麼它只負責對自身進行繪製。this

c)

   Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring pass is implemented in measure(int, int) and is a top-down traversal of the View tree. Each View pushes dimension specifications down the tree during the recursion. At the end of the measure pass, every View has stored its measurements. The second pass happens in layout(int, int, int, int)and is also top-down. During this pass each parent is responsible for positioning all of its children using the sizes computed in the measure pass.

繪製須要兩個過程,一個是measure(測量大小的)過程,一個是layout(計算繪製位置的)過程:

1)measure過程:須要在measure()方法中實現,而且是自頂向下地遍歷測量View的樹形結構,測量完後,各結點將它的測量規格(specifications)存放在該樹形結構中;

2)layout過程:經過調用layout(int,int,int,int)方法,每個父View負責子View的繪製位置,而子View的最終大小,則是經過measure過程計算出來的大小。

d)

         When a View object's measure() method returns, its getMeasuredWidth() and getMeasuredHeight() values must be set, along with those for all of that View object's descendants. A View object's measured width and measured height values must respect the constraints imposed by the View object's parents. This guarantees that at the end of the measure pass, all parents accept all of their children's measurements. A parent View may call measure() more than once on its children. For example, the parent may measure each child once with unspecified dimensions to find out how big they want to be, then call measure() on them again with actual numbers if the sum of all the children's unconstrained sizes is too big or too small (that is, if the children don't agree among themselves as to how much space they each get, the parent will intervene and set the rules on the second pass).

  當每一個View對象的measure()方法返回時,每一個View的測量寬度值跟測量高度值必須已經被設置,且這兩個值是與該View對象的父View相互做用下得來的,並非說每一個View對象都能請求到它任意想獲得的值,若是這個View對象請求的寬度或者高度不合理,那麼,這個View對象的父View,將再次調用measure()方法,再次肯定這個View對象的最終寬度和高度,這個將在後面的onMeasure()過程詳細說明中解釋;

e)

The measure pass uses two classes to communicate dimensions. The ViewGroup.LayoutParams class is used by View objects to tell their parents how they want to be measured and positioned. The base ViewGroup.LayoutParams class just describes how big the View wants to be for both width and height. For each dimension, it can specify one of:

1)an exact number:
2)MATCH_PARENT:
which means the View wants to be as big as its parent (minus padding) 3)WRAP_CONTENT:
  which means that the View wants to be just big enough to enclose its content (plus padding). There are subclasses of ViewGroup.LayoutParams for different subclasses of ViewGroup. For example, RelativeLayout has its own subclass of ViewGroup.LayoutParams, which includes the ability to center child View objects horizontally and vertically. MeasureSpec objects are used to push requirements down the tree from parent to child. A MeasureSpec can be in one of three modes: UNSPECIFIED: This is used by a parent to determine the desired dimension of a child View. For example, a LinearLayout may call measure() on its child with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how tall the child View wants to be given a width of 240 pixels. EXACTLY: This is used by the parent to impose an exact size on the child. The child must use this size, and guarantee that all of its descendants will fit within this size. AT MOST: This is used by the parent to impose a maximum size on the child. The child must guarantee that it and all of its descendants will fit within this size.

測量過程使用兩個類與dimensions(尺寸)進行通信,這兩個類分別是ViewGroup.LayoutParams和MeasureSpec

ViewGroup.LayoutParams:

  用來讓View對象告訴他的父View,它須要如何被測量和放置在什麼位置,然而,ViewGroup.LayoutParams只是單方面地描述它本身想要多大的寬度和高度而已,並非最終繪製出來的寬度和高度,ViewGroup.LayoutParams能夠指定爲如下的值:

1)an exact number:
  具體的數值; 2)MATCH_PARENT:
與父容器同樣的大小; 3)WRAP_CONTENT:
  自己該多大就多大,根據該View的內容而定,如TextView中,若是將其寬度設置爲wrap_content,那麼,它將隨着text的長度而改變它的寬度。

MeasureSpec:

  該對象封裝了父容器傳遞給子元素的佈局要求,它有三種模式:

1)
UNSPECIFIED:父容器對子元素沒有要求,子元素能夠獲得任意值;
2)
EXACTLY:父窗口決定子元素的大小,子元素將被限定在給定的邊界裏而忽略它自己大小;
3)
AT MOST:子元素至多達到父窗口指定的大小,子元素不能超過這個邊界;
相關文章
相關標籤/搜索