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)

CustomViewActivity.java

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)

customview_layout.xml

 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)運行結果:

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

a)

查看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)

   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等),那么它只負責對自身進行繪制。

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:子元素至多達到父窗口指定的大小,子元素不能超過這個邊界;
 


 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM