2012-03-17

使用 SurfaceView 介面來處理貼圖

如果不使用 Android 現成的 Widget (ImageView 與 ImageButton) 來處理圖片的話, 我覺得要在 Android 中貼圖並不是很方便, 從引用圖片來源開始, 一直到圖片的呈現, 整個過程十分冗長; 況且處理圖形的指令總是一長串 ... 但是, 現成的 Widget 也不一定能符合設計者的需要, 當應用程式需要較高的顯示效率與較獨特的操作介面時 (如遊戲軟體), 那麼那些方便的 Widget 就不太適合了 !

這篇的重點就在於使用 SurfaceView 介面來進行貼圖的動作, SurfaceView 介面最適合開發顯示速率較快的應用程式, 不過, 使用這個介面來處理圖片並不輕鬆 ! 就像我前面說過的那樣, 而且整個過程一開始並不容易理解, 一時之間也不容易解釋清楚, 那 ~ 有沒有淺顯易懂的方式 ? 我的答案是 -- 沒有 ! 建議你, 只有透過不斷的練習, 才能熟練它 ! 進一步理解它 !

我使用 SurfaceView 介面貼了一張圖, 如下 :

只貼一張圖, 座標 x : 50 , y : 100

程式碼如下 : (紅色字體為重點)
大部份的註解我順便寫在程式碼內了

// 主程式
public class surfaceviewTest extends Activity {
    /** Called when the activity is first created. */
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        DrawTest drawTest = new DrawTest(this);
        setContentView(drawTest);
    }
}

==========================================

// 另一個類別 surfaceviewTest
public class DrawTest extends SurfaceView implements SurfaceHolder.Callback {
   
    //呼叫getHolder()方法來取得 SurfaceHolder,並指給 holder
    SurfaceHolder holder = getHolder();
    Bitmap bp;
    Canvas canvas;
    int x=50,y=100;  //貼圖在螢幕上的 x,y 座標

    // DrawTest 建構子
    public DrawTest(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
       
        //把這個 class 本身(extends SurfaceView)
        //透過 holder 的 Callback()方法連結起來
        //下面這行也可寫成 getHolder().addCallback(this);
        holder.addCallback(this);
       
        //設定圖片來源(此處使用預設的圖片)
        bp = BitmapFactory.decodeResource(getResources(),
                                                  R.drawable.icon);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub

        //在 canvas 畫布上貼圖的三個步驟

        //1. 鎖住畫布
        canvas = holder.lockCanvas();
        //2. 在畫布上貼圖
        canvas.drawBitmap(bp,x,y,null);
        //3. 解鎖並po出畫布
        holder.unlockCanvasAndPost(canvas);
    }
   
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
    }
}
==============================================

與 SurfaceHolder.Callback 相關聯的三個程序 :
public void surfaceCreated(...) -- surface 建立時
public void surfaceChanged(...) -- surface 改變時
public void surfaceDestroyed(...) -- surface 結束時

上述貼圖的主要步驟是寫在 surfaceCreated 程序中
一張靜態的圖是看不出 SurfaceView 的能力的, 如果要讓圖 "動"起來, 則還需要配合執行緒的運用, 透過執行緒不斷去改變圖片的座標並反覆貼上圖片, 就可以達到動態的效果囉 ! 想朝 Android App 遊戲相關的應用軟體發展, 練習在 SurfaceView 中貼圖只是一個開端, 先從這個基礎出發, 再配合物件導向的程式架構及執行緒的應用, 才能建構出一個完整的應用程式 .^_^.

您可以延伸閱讀本部落格使用 SurfaceView 類別的其他範例 :

動態物件的產生與捕捉
模擬物件的生命週期
模擬拖曳小圖示的 Android 程式

2012-03-16

Android 的 xml 檔案 (三) AndroidManifest.xml

AndroidManifest.xml 檔, 或稱為 [ 應用程式設定檔 ], 這個 xml 檔比較特殊一點, 每個應用程式都需要配置一個 Manifest.xml 檔, 如果要簡單解釋它的功用, 你可以把它想成是 [ 應用程式 ] 在執行前與 [ Android 系統架構 ] 之間所訂定的一種規範準則.

嗯 ... 講白話一點的話 ~ 就好比你進到電影院裡面, 按照你想看的電影與場次, 買了電影票, 然後你循著電影票上的資訊 : 場次、入場時間、哪一廳、座位號碼 ... 從進場就座到看完電影, 走出戲院. 這整個流程 ~ 你自己就好比是一個 [ 應用程式 ], 而整個電影院就好比是 [ Android 系統架構 ], 那張電影票就是 [ Manifest.xml 檔 ], 試想如果沒有遵循那張電影票上的資訊, 你在電影院內又該如何順利欣賞到電影 ? 這樣有沒有概念了呢 ? 哈哈哈 ~ 當然這只是比喻而已, 實際上還要更複雜些 ! >"<

先想像你自己是個 [ 應用程式 ], 這張就是你的電影票 ~ 哈哈哈!

在這裡僅就其中主要的幾個部份做介紹 :

 <manifest xmlns:android="http://schemas...(略)"
      package="a.b.c"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />
    ......... (略, 內容列在下方)
</manifest>

開頭是以 <manifest>   .....  以 </manifest> 為結尾
代表此檔案為 Manifest.xml, 上述區段中包含了版本號碼之類的資訊.

<uses-sdk android:minSdkVersion="7" />
這行宣告, 表示你的應用程式適用在哪個 Android 系統版本上運作. 這個重要 ! 藉此聲明低於這個版本代號的 Android 系統就不適合安裝此應用程式囉 ! 上述的版本代號為  7 ( 對應版本實際為 2.1, 在此檔案中僅以代號表示 ) 在創建新專案時已先指定此參數了, 不需在此做更動.

下方是僅包含一個 activity 的應用程式設定檔內容 :

<application android:icon="@drawable/icon"   
                     android:label="@string/app_name">
        <activity android:name=".StrAndInt"
                  android:label="@string/app_name">
           <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
</application>

開頭以 <application> .... </applicatio n> 做結尾, 表示此區段的內容與應用程式有關.

<application> ~ </application>區段內各行的簡介:

android:icon="@drawable/icon"
此應用程式的圖示

android:label="@string/app_name"
此應用程式的名稱, 由於名稱已寫入 strings.xml 檔中, 所以在此看不到 ~ 此範例的 @string/app_name 變數內容為 "StrAndInt"

<activity android:name=".StrAndInt"
activity 在程式內的名稱為 "StrAndInt", activity 可想成是應用程式的初始架構.

android:label="@string/app_name">
activity 顯示在外的名稱, 此名稱已寫入 strings.xml 中, 此變數內容是 "StrAndInt"

<intent-filter> .... </intent-filter>
定義此 activity 的性質與內容

<action android:name="android.intent.action.MAIN" />
程式的進入點 (表示開頭由此 activity 先執行)

<category android:name="android.intent.category.LAUNCHER" />
應用程式出現的位置 ... 這個用圖說明比較清楚 ~ 下面兩張圖

按下紅框處進入應用程式選單

在此選單中可以看見此應用程式的圖示與名稱


上面的 AndroidManifest.xml 檔的內容較為陽春, 這個設定檔還可定義應用程式需啟用何種服務及宣告是否擁有兩個以上的 activity (只能選一個 activity 為程式啟始點), 其他細節部份留待您自行去學習, 本文僅作簡單介紹, 內容難免粗糙及疏漏, 尚請見諒 !  .^_^.

#本文僅就 xml 檔的概念來闡述, 其他細節請自行參考相關書籍.

2012-03-15

Android 的 xml 檔案 (二) main.xml

上次談了 strings.xml 檔案, 這次我來談談 main.xml 檔案.
main.xml 檔的作用就是用來設計畫面的格局; 有的人稱其為 [佈局檔], 預設是 main.xml, 如果你的應用程式要呈現一個以上的佈局畫面 (切換不同的畫面), 那麼你也可以設計多個佈局檔, 並且在一個 Activity 中輪番使用, 但是名稱不可相同, 例如 main.xml, main2.xml ... 至於何時該呈現哪個佈局畫面, 則必須透過程式來控制, 例如 :
if (條件)  setContentView(main.xml)  else  setContentView(main2.xml)

不過, 要想這麼做的話, 不如多創建一個 Activity 還來得比較實際些, 一個 Activity 控制一個佈局檔才不會把問題越搞越複雜.


main.xml 是否需要手動編寫 ?
在 Android 開發工具中提供了 Graphical Layout 功能, 讓開發者可以很方便地以拖曳元件的方式來佈置顯示畫面, 如下圖所示 :

Graphical Layout 設計視窗

在 Graphical Layout 設計視窗中, 可從左側的工具箱中將元件拖曳到畫面顯示區, 下方的 Properties 欄位還可以設定該元件的各項屬性, 這種直覺的設計方式為設計者省下不少寶貴的時間.

如下圖 :
我放置了一個 Button, 一個 TextView 及 一個 RatingBar, 共三個元件, 當你拖曳元件到顯示區後 (或刪除元件), 其對應的 xml 檔中 (此例為 main.xml) 亦會同步自動產生此畫面佈局的語法內容.


我們再從 Graphical Layout 視窗切換到 main.xml 視窗來看一下 xml 檔的對應內容, 天哪 ! 才放了三個元件而已, xml 檔的內容竟然那麼多 !

============================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:baselineAligned= "false"
android:layout_height="wrap_content"
android:orientation= "vertical" android:layout_width="fill_parent">
    <LinearLayout android:id="@+id/linearLayout1" android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:baselineAligned="true">
        <Button android:id="@+id/button2" android:layout_height="wrap_content"
android:text="Button" android:layout_width="wrap_content" android:layout_gravity="right"> </Button>
        <TextView android:id="@+id/textView2" android:layout_height="wrap_content"
android:text="TextView"
android:layout_width="wrap_content" android:textSize="30sp" android:layout_gravity="top"> </TextView>
    </LinearLayout>
    <RatingBar android:id="@+id/ratingBar1" android:layout_width="wrap_content"
android:layout_height="wrap_content"> </RatingBar>
</LinearLayout>
=============================================

如果沒有 Graphical Layout 的協助, 光是徒手編寫這些內容就夠累人的了 ! 更不用說還要撰寫後續的程式碼來控制這些元件. 不過呢 ~ 也不要太依賴 Graphical Layout 的功能喔.

有幾次我在設計時不小心按錯幾個功能項, 畫面中的元件位置因此大亂 ~ 不管怎麼調整還是調不回來, 有時是越調越亂 ! 遇到這種情形時, 我會切換到 xml 檔中直接去修改出問題的地方; 所以 ~ 先把 Graphical Layout 功能當做輔助工具, 必要時再直接去修改 xml 檔的內容會是比較好的做法 !

上述只是我的經驗分享, 如果你已經建立好你的工作方式, 請依照你原先的習慣就好 .^__^.

#本文僅就 xml 檔的概念來闡述, 其他細節請自行參考相關書籍.

2012-03-14

Android 的 xml 檔案 (一) strings.xml

當你創建了一個 Android Project (專案), ADT (Android 開發工具) 預設會建立三個 xml 檔案, 看下圖 : (畫紅線處)


預設有三個 xml 檔


main.xml : 畫面佈局檔

strings.xml : 字串資源檔

AndroidManifest.xml : 應用程式設定檔

這一篇先來說說 strings.xml 檔 :
運用 xml 檔的好處就是 [資源] 與 [程式碼] 可以分別處理. 這種將兩者分離的方式在編寫龐大的應用程式與字串資料時是非常有效率的機制.

開發工具提供了兩種介面可以編寫 strings.xml 檔的內容 : (如下圖)

介面一 : 配合說明與指引方式編寫內容
介面二 : 直接手動編寫內容

至於 strings.xml 檔的優點,下面是我整理出來的心得 :

strings.xml 檔的便利性 :
如果應用程式中需要用到的字串資料都直接寫進程式原始碼的話, 當遇到需要修改那些字串資料時, 勢必得在成堆的程式碼中一一將它們找出來並加以修改, 尤其當程式碼相當龐大時, 去修改那些寫進程式碼的字串資料是件非常沒有效率的事情 ! 況且 ~ 每次修改完程式原始碼還要重新編譯一次 ! 此時, 只需要單獨對 strings.xml 檔的資料做修改與存檔即可, 不會造成牽一髮而動全身的窘況.

strings.xml 的最大功效在於多國語系資料的應用 :
當你要設計有支援多國語系的應用程式時, 可在 strings.xml 中建立好你要支援的各語系資料, 使用者只需在程式運作前選好語系, 在應用程式執行時, 程式中的變數就能準確地把對應到 strings.xml 中的資料取出來. 假設不透過這個機制的幫忙, 單純只以程式來做多國語系的切換 ... 其複雜程度將難以想像 !

#本文僅就 xml 檔的概念來闡述, 其他細節請自行參考相關書籍.

如何截取 Android 模擬器的畫面

這一篇的重點在於如何截取 Android 模擬器的畫面, 在這之前先來談一下一般的螢幕截圖方式.

如何截取電腦螢幕的畫面, 這個小技巧我想應該很多人都會了吧 !
還不會 ? 讓我們來復習一下 ~

按下鍵盤的 Ptr Scrn / Sys Rq 鍵 (該鍵的位置在鍵盤偏右側上方, 有些鍵盤標示的字樣不同, 請找一下) 就可以把整個螢幕內容 Copy 到剪貼簿, 然後再將剪貼簿的內容用滑鼠右鍵 (貼上) 貼到小畫家或可以編輯圖檔的應用軟體中, 再進行縮圖或改圖 !

如果要用上述的方式來截取 Android 模擬器的畫面也是可以, 但後續還要將其主要畫面另外截取出來, 不是很方便; 況且截取範圍要是沒有選取好的話, 邊框看起來總是不太順.

幸好, 結合了 Android 開發工具的 Eclipse 編輯器, 其中就有一個貼心的功能讓我們可以很方便截取模擬器的畫面.

首先, 必須先讓 Android 模擬器啟動 (模擬器設定細節不在本文討論範圍), 啟動模擬器的方法如下圖所示 :

啟動 Android 模擬器的方式
功能表 -- Windows > Android SDK and AVD Manager
(其他設定細節非本文重點, 略過)

假設您的 Android 模擬器已經成功開啟
請按下 Eclipse 右上角的 DDMS 選項 (如下圖)
小圖示顯示為一 Android 綠色機器人圖樣, 或僅顯示 DDMS 字樣  
如果 DDMS 選項沒有出現, 請按下面步驟將 DDMS 選項叫出 :
功能表 -- Windows > Open Perspective > Other > DDMS
 
在 Eclipse 編輯器右上方按下 DDMS 選項

請按照紅圈標示的步驟 :
1 : DDMS 選項按下後, 進入 DDMS 管理畫面
2 : 接著按下 Screen Capture, 會呈現目前 Android 模擬器的畫面 

進入 DDMS 管理畫面


Screen Capture 視窗有幾個功能選項 : (如下圖)

Refresh : 立即更新模擬器目前的顯示狀態
Rotate : 旋轉模擬器畫面
Save : 存檔 ~ 以 png 格式存檔
Copy : 把模擬器的畫面直接拷貝到剪貼簿中
Done : 關閉此視窗, 與按右上方的 X 鈕相同

Android 模擬器的 Screen Capture 操作畫面

很簡單吧 ! 趕快操作看看 !

搜尋此網誌