網頁

2010年12月13日 星期一

Android: 讀書心得 #5 2D繪圖基礎概念

接續上篇: 花栗鼠柑仔店: Android筆記: 讀書心得#4

參考資料: Amazon.com: Hello, Android: Introducing Google's Mobile Development Platform (Pragmatic Programmers) (9781934356562): Ed Burnette: Books

這段內容主要為:
第4章 2D繪圖
4.1 2D繪圖基礎概念

第4章: 2D繪圖 (Exploring 2D Graphics)

好的圖形設計可以讓任何程式看起來較為有趣吸引人, Android放了不少強大的圖形函式庫, 讓開發者可在行動裝置中開發有趣的應用程式. 實際上主要的是一個是2D繪圖設計用, 另外一個是3D繪圖設計用, 這章所提到的是2D繪圖部分讓你可以實作Sudoku遊戲, 在第10章會再提到3D繪圖在OpenGL部分, 之後也會提到用OpenGL ES函式庫來處理3D繪圖部分. (功能上Android有考量到4D, 但是因為時間考量後來先被捨棄了)

4.1 2D繪圖基礎概念
Android的2D圖形處理函式庫主要是放在android.graphics, 底下介紹幾個需要瞭解的基本類別.

(1) Color

Android中顏色被四個數值所代表: ARGB (Alpha, Red, Green, Blue), 每個數值為8 bits, 也就是0-255, 所以一個顏色所需要的數值是8 Bits*4=32 Bits 整數. 為了效能考量, Android的程式碼使用一個整數來代表顏色, 而不是產生一個Color類別的實體. RGB三個數值不需說明即可瞭解, 但Alpha這數值是代表透明度(measure of transparency), 最低值為0, 代表顏色完全透明, 不管RGB的值為何, 假如A是0就是整個看不見, 最高值為255, 也就是不透明(opaque), 中間值用來代表 透亮 (translucent), 半透明 (semitransparent), 有顏色(colors), 讓你可以稍微看到銀幕上所繪物件底下有什麼東西.

程式中假如要定義一個藍色, 可以用Color類別指定如下:
int color = Color.BLUE; // solid blue

或你可以知道四個數值ARGB, 可用Color類別中argb的靜態函式宣告一個透亮的紫色:
// Translucent purple
int color = Color.argb(127, 255, 0, 255);

另外也可以用XML資源檔來設定:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="mycolor">#7fff00ff</color>
</resources>

在程式中要使用到XML資源檔的話可以用getResources()來取得:
int color = getResources().getColor(R.color.mycolor);

getResources()會回傳目前activity的ResourceManager類別, 再來用getColor()與資源ID即可取得所需要的顏色定義.

(2) Paint
Paint是Android圖形函式庫中最重要的類別, 裡面包含了各式如style, color與其他用來繪圖所需的相關資訊, 包括繪出文字, 圖形等等. 一般我們要在銀幕上畫出某個顏色的東西, 可以利用Paint.setColor( )方法來設定, 如底下這程式代表設定要畫出淺灰色:

cPaint.setColor(Color.LTGRAY);

(3) Canvas
Canvas(畫布)代表可讓你"畫上去"的表面, 一開始裡面是空無內容, Canvas類別中的方法可以讓你在表面上畫出線, 方形, 圓圈, 與任意圖形. 在Android中, 顯示銀幕是被Activity所佔據, 而Activity是建構在View之上, View又是建構在Canvas之上, 所以你可以重載View.onDraw(), 在其中的Canvas下一些繪圖命令, 控制你想要畫什麼在View中, 底下一個重載onDraw()的範例:

public class Graphics extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new GraphicsView(this));
  }

  static public class GraphicsView extends View {
    public GraphicsView(Context context) {
      super(context);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    // Drawing commands go here
  }
}


(4) Path
Path(軌跡)類別裡頭包含了一些向量繪圖的命令, 如線, 圓, 曲線等等, 底下是一個範例定義一個圓的軌跡(path):

circle = new Path();
circle.addCircle(150, 150, 100, Direction.CW);

上面的程式碼定義了一個圓, 其圓心XY座標均為150, 而半徑為100, Direction.CW代表順時鐘方向, 我們可以利用這個圓的軌跡, 沿著他的內部順時鐘畫一段文字:

private static final String QUOTE = "Now is the time for all " +
"good men to come to the aid of their country." ;
canvas.drawPath(circle, cPaint);
canvas.drawTextOnPath(QUOTE, circle, 0, 20, tPaint);

顯示在畫面的結果如下:

假如需要很炫的效果, Android有提供一組(6個?)PathEffect軌跡效果類別可供使用, 如亂數排列(random permutation)之類, 讓所有在軌跡上的線段平滑化或分開線段, 建構其他軌跡效果等等.

(5) Drawable
Android中Drawable類別是用來定義一個可視元素如點陣圖或單色之類可用來顯示的元素,(事實上在Android中, Drawable類別是一個抽象類別, Drawable | Android Developers) 你可以結合可繪元素(drawables)與其他圖形, 或你可以使用這些可繪元素在使用者介面的工具集上(user interface widgets), 如將可繪元素當成按鈕或view的背景. Drawable類別有底下不同的類型(android.graphics.drawable | Android Developers):
  • Bitmap: 一個PNG或BMP圖
  • NinePatch: 可伸縮(stretchable)的PNG圖, 會這樣命名是因為其原本將圖本身分成九個區塊, 常用在可改變大小點陣按鈕的背景圖.
  • Shape: 向量繪圖指令, 以Path為基礎, 可視為"窮人版"的SVG(功能類似, 但不及SVG).
  • Layers: 用來裝子drawabless的容器, 也可以以某個z順序(z-order)來互相繪在Layers上面.
  • States: 用來顯示子drawables的容器, 裡面以狀態(a bit mask, 位元遮罩)來排序, 一種用途是設定按鈕不同的選擇與重點狀態.
  • Levels: 基於其level值(一段整數)來顯示單一個子drawables的容器, 可用在如電池或訊號強度的計量器.
  • Scale: 用來存一個子drawable基於其目前level修改其大小的容器, 一種用法可能是可便大小的影像檢視器.


Drawables通常以XML的形式定義. 底下是一個drawable一般的例子, 其中定義了一個漸層色(gradient)從白到灰, 其漸層的方向角度為270度, 270度代表由上到下, 底下的例子可用在背景view上:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
  <gradient
    android:startColor="#FFFFFF"
    android:endColor="#808080"
    android:angle="270" />
</shape>

要使用上述XML中所定義的顏色, 可在Layout檔中的屬性: android:background=...中設定, 或在view中以setBackgroundResource()來定義(放在onCreate()方法中):
setBackgroundResource(R.drawable.background);


執行結果會如下:



Drawables應該放在不同的目錄, 取決於其所設計對應的銀幕的解析度.

(第4章 2D繪圖 未完待續)

3 則留言:

  1. 我想請問一下 那串字可以只訂從哪一個角度開始繞嗎?
    列如我想要"Now..."開頭從九點鐘方向繞一個圈
    拜託版主解惑一下謝謝

    回覆刪除
  2. 你好,
    你要的功能應該是改這個吧?
    canvas.drawTextOnPath(QUOTE, circle, 0, 20, tPaint);
    請參考手冊:
    http://developer.android.com/reference/android/graphics/Canvas.html

    回覆刪除