public class EX05_31 extends Activity private ImageView imageview01; private ImageView imageview02; private Button button01; public void oncreatebundle savedinstancestate) super.oncreatesavedinstancestate setcontentviewr.layout.main /* 物件初始化 */ imageview01 = ImageView)findViewByIdR.id.imageView01 imageview02 = ImageView)findViewByIdR.id.imageView02 button01 = Button)findViewByIdR.id.button01 /* 設定 ImageView 的 OnClick 事件 */ imageview01.setonclicklistenernew OnClickListener) public void onclickview arg0) new AlertDialog.BuilderEX05_31.this).setMessage"Android SDK 開發範例大全!").setNeutralButton"OK", null).show imageview02.setonclicklistenernew OnClickListener) public void onclickview arg0) new AlertDialog.BuilderEX05_31.this).setMessage"Android SDK 開發範例大全 2!").setNeutralButton"OK", null).show /* 按下按鈕後觸發駭客事件 */ button01.setonclicklistenernew Button.OnClickListener) public void onclickview view) HackerView hview = HackerView) getlayoutinflater).inflater.layout.hacker_layout, null 5 483
hview.setactivitytospoofex05_31.this /* 以 Toast 的方式覆蓋原先顯示的 Activity*/ Toast toast = new ToastgetApplicationContext) toast.setgravitygravity.fill, 0, 0 toast.setviewhview toast.setdurationtoast.length_long toast.show src/irdc.ex05_31/hackerview.java 自訂 HackerView, 繼承 ViewGroup, 當中的 setactivitytospoof 這個 method 是在主程式建構 HackerView 物件 hview) 後, 為了將 Activity 的 Context 傳入, 以便於自訂函數 spooflayout) 調整 Hacker 畫面元件位置與原本的位置相同 /* import 程式略 */ import android.view.viewgroup; /* 自訂 HackerView, 繼承 ViewGroup */ public class HackerView extends ViewGroup /* 成員變數為 EX05_31 Activity Context*/ private EX05_31 mactivity; public HackerViewContext context, AttributeSet attrs) supercontext, attrs public void setactivitytospoofex05_31 activity) this.mactivity = activity; protected void onmeasure int widthmeasurespec, int heightmeasurespec) measurechildrenwidthmeasurespec, heightmeasurespec super.onmeasurewidthmeasurespec, heightmeasurespec 484 Google Android SDK 3
protected void onlayout boolean changed, int l, int t, int r, int b) /* 調整 Layout, 使其與原來畫面看起來一模一樣 */ /* 左邊的 ImageView*/ spooflayout findviewbyidr.id.hacker_imageview01), mactivity.findviewbyidr.id.imageview01) /* 右邊的 ImageView*/ spooflayout findviewbyidr.id.hacker_imageview02), mactivity.findviewbyidr.id.imageview02) /* 下方的 Button 按鈕 */ spooflayout findviewbyidr.id.hacker_button01), mactivity.findviewbyidr.id.button01) /* 調整 Hacker 畫面元件位置的 method*/ private void spooflayoutview spoof, View original) final int[] globalpos = new int[2]; getlocationonscreenglobalpos int x = globalpos[0]; int y = globalpos[1]; original.getlocationonscreenglobalpos x = globalpos[0] - x; y = globalpos[1] - y; spoof.layout x, y, x + original.getwidth), y + original.getheight) 5 485
res/layout/main.xml 要使用 touch filtering 的手法非常容易, 僅需在定義 UI 的 XML 時加上一個屬性 : android:filtertoucheswhenobscured="true" 即可 以下為節錄 main.xml 中, 兩個 ImageView 的定義敘述, 除了圖片的 src 不同之外, 僅多了一行 android:filtertoucheswhenobscured 的屬性定義 <ImageView android:id="@+id/imageview01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/android1" android:padding="5sp"/> <ImageView android:id="@+id/imageview02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/android2" android:padding="5sp" android:filtertoucheswhenobscured="true"/> 除了在 main.xml 裡加上 android:filtertoucheswhenobscured 屬性定義外, 也可以利用程式的寫法 執行結果同範例 EX05_31), 但將防止背景物件點擊的方法寫在程式裡面, 同樣可以達到背景物件不會被點擊到的效果 /* 主程式的 oncreate)*/ settouchfilterimageview02 /* 防止背景事件被觸發的 method*/ private void settouchfilterimageview view) view.setontouchlistenernew OnTouchListener) public boolean ontouchview v, MotionEvent event) ifevent.getflags) & MotionEvent.FLAG_WINDOW_IS_OBSCURED)!= 0) return true; 486 Google Android SDK 3
10-18 10-13 GestureDetector SurfaceView RSS 不知何時開始, 宅男 腐女 已成過時的流行語, 取而代之的是 女神 犀利人妻 神人 等, 但有些語彙在時空的快速流逝中很難消失, 正妹 如是, 型男 如是 若在網路搜尋引擎裡輸入上述關鍵字, 相信得到的搜尋結果少說也有數千萬筆 本範例將透過網際網路連結至 Picasa 相簿進行關鍵字搜尋, 搜尋的結果除了可即時在畫面上呈現之外,PicasaWeb 亦提供查詢結果的 RSS Feed 範例程式以搜尋 美女 作為 PicasaWeb 關鍵字的查詢練習, 以 Java 解析 XML 類別 org.xml.sax.helpers.defaulthandler 作為建構解析 RSS 物件,DefaultHandler 為 SAX2 事件處理的基底類別 base class), 請自訂一個名為 PhotoHandler 類別, 使之繼承自 DefaultHandler, 然後將取得圖片網址存入 List 10 Android 1243
在 UI 畫面中並不在 main.xml 預先定義 SurfaceView, 而是在程式 oncreate) 時, 動態新增一個 SurfaceView 至 UI 上, 但這個 SurfaceView 因為要辨識手勢事件, 所以, 此範例需要自訂一個繼承自 SurfaceView 的 MySurfaceView, 並在自訂的類別中建立 GestureDetector 物件, 判斷 User 在觸控螢幕上的左右滑動手勢, 當向左滑動, 表示畫面往左拉, 手勢向右滑動, 則畫面往右拉, 而每次滑動都會即時至 PicasaWeb 相簿裡下載圖片至 SurfaceView 裡顯示 欲實作此程式有幾個必備知識 :SurfaceView 繪圖 網路下載圖片 GestureDetector 手勢判斷, 以及 XML Parser 等 在本書前幾章都有範例練習上述關鍵程式, 以下是程式預期的執行結果 10-19 src/irdc.ex10_13/ex10_13.java 主程式將 ontouchevent) 與 mygesturelistener) 繫結在一起, 當手指觸碰螢幕觸發某種事件時,myGestureListener 會呼叫 MySurfaceView 中相對應的 method 如 :mmysurfaceview01.ondown) 與 mmysurfaceview01.onup) 等 ), 處理 SurfaceView 究竟是按下或者是手指離開觸控螢幕, 如範例程式碼所示, 建構 MySurfaceView 時, 需要傳入三個參數, 第一個為此 Activity 的 Context, 第二 1244 Google Android SDK 3
第三則是現有螢幕的解析度, 作為在 MySurfaceView 類別中, 與原來 Activity 溝 通與繪圖的管道 /* import 程式略 */ import android.view.gesturedetector; import android.view.motionevent; public class EX10_13 extends Activity private LinearLayout mlayout01; private MySurfaceView mmysurfaceview01 = null; private GestureDetector mgesturedetector01; private mygesturelistener mgesturelistener01; private int width=0; private int height=0; public void oncreatebundle savedinstancestate) super.oncreatesavedinstancestate /* 全螢幕顯示 */ getwindow).setflags WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN requestwindowfeaturewindow.feature_no_title setcontentviewr.layout.main /* 取得螢幕寬高 */ width=getwindowmanager).getdefaultdisplay).getwidth height=getwindowmanager).getdefaultdisplay).getheight /* 建立 MySurfaceView 物件 */ mlayout01 = LinearLayout) findviewbyidr.id.mylinearlayout1 /* 讓 MySurfaceView 成為充滿視窗的 Layout 參數 */ LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT /* 建構自訂 MySurfaceView 物件 */ mmysurfaceview01 = new MySurfaceView /* 將 Context 傳入 */ EX10_13.this, // 圖檔寬 高 10 Android 1245
width,height /* 將自訂 mmysurfaceview01 動態配置於 Layout*/ mlayout01.addviewmmysurfaceview01, llp public boolean ontoucheventmotionevent event) /* 捕捉手指按下與放開的動作 */ ifevent.getaction)==motionevent.action_down) mmysurfaceview01.ondown else ifevent.getaction)==motionevent.action_up) mmysurfaceview01.onup /* 有 TouchEvent 發生時觸發 mygesturelistener */ if mgesturedetector01.ontoucheventevent)) return mgesturedetector01.ontoucheventevent else return super.ontoucheventevent /* 自訂 GestureDetector.OnGestureListener */ public class mygesturelistener implements GestureDetector.OnGestureListener public boolean onscroll MotionEvent e1, MotionEvent e2, float distancex, float distancey) /*Scroll 事件發生時執行 MySurfaceView 的 handlescroll)*/ mmysurfaceview01.handlescrolle2.getx)-e1.getx) return false; public boolean ondownmotionevent e) return false; 1246 Google Android SDK 3
11-02 HTML5 CSS3 CSS3 求學時, 筆者曾在校外附近的餐廳用餐, 店家用相片紀錄許多歡樂的氣氛照片, 貼在牆上作為佈置, 多年後回到學校演講, 再次光顧那家餐廳, 雖然裝潢隨時空轉變大不相同, 牆上留有當年相片依舊, 卻回味萬千 這個範例程式是一個以 CSS3 排版的牆貼相簿, 有別於傳統 HTML 以 <img> 標籤所組成的四四方方的相片排版, 每一張照片都可以擁有自己的旋轉角度, 並模擬以動態載入圖片的情形 預先將 gallery.html 網頁檔案與九張相片存放在 /assets/gallery.html 與 /assets/image/*.jpg 資料夾下, 作為 UI 畫面上部署 WebView Widget 的載入頁面參考檔案, 當頁面載入完畢時, 再利用 JavaScript 置換 HTML5 網頁裡的 DIV 圖層, 來放入排好版型的 CSS5 相片樣式, 呈現出美觀的照片集 11-2 CSS3 HTML5 10 Android 1277
src/irdc.ex11_02/ex11_02.java 程式的私有人員變數中, 宣告了四個 String[]: indx 為相片層級 rotate 為相片旋轉角度 sphoto 為相片檔案名稱 name 為相片中文名稱, 這四個 String[] 用在組成 CSS3 排版的 HTML5 TAG 當程式一執行 oncreate) 時, 便會透過 findviewbyid 初始化 WebView 物件 mwebview01), 接著呼叫自訂函數 initwebviewlistener) 來重組本範例的關鍵 CSS3 與 HTML 標籤, 經過程式的 For 迴圈重組產生 HTML 語法標籤 htmlpath), 迴圈中透過 CSS 的 z-index 控制每張照片的交疊層級, 用 -webkit-transform:rotate) 控制照片的旋轉角度, 然後讓 WebView 載入 /assets/gallery.html 網頁, 由於需要以動態的方式置換 gallery.html 中 ;DIV 圖層 mycontent) 裡的 innerhtml, 故設定 mwebview01 的 WebSettings.setJavaScriptEnabled 屬性來啟用 JavaScript, 最後, 當網頁載入完畢時 onpagefinished), 將 htmlpath 置換掉, 顯示以 CSS3 排好版的相片 /* import 程式略 */ public class EX11_02 extends Activity private String data=""; private WebView mwebview01; private String htmlpath = "file:///android_asset/gallery.html"; /* 相片層級 */ private String[] indx=new String[] "4","1","2","8","6","9","3","5","7" ; /* 相片旋轉角度 */ private String[] rotate=new String[] "4","20","-5","15","-10","10","20","-10","-6" ; /* 相片檔名 */ private String[] sphoto=new String[] "s1.jpg","s2.jpg","s3.jpg","s4.jpg","s5.jpg", "s6.jpg","s7.jpg","s8.jpg","s9.jpg" ; /* 相片名稱 */ private String[] name=new String[] 1278 Google Android SDK 3
; " 國慶煙火 "," 蘭陽博物館 "," 東華大學 ", " 南寮夕景 "," 日月潭 "," 合歡山 ", " 油菜花田 "," 大武崙漁港 "," 竹子湖 " public void oncreatebundle savedinstancestate) super.oncreatesavedinstancestate /* 全螢幕設定 */ getwindow).setflags WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN requestwindowfeaturewindow.feature_no_title setcontentviewr.layout.main /* WebView 設定 */ mwebview01 = WebView) findviewbyidr.id.mywebview1 /* 不使用快取機制, 每次皆重新載入新圖 */ mwebview01.getsettings).setcachemode WebSettings.LOAD_NO_CACHE /* 執行 WevView 初始化與載入網頁 */ this.initwebviewlistener /* 初始化 WebView 的 method */ private void initwebviewlistener) mwebview01.getsettings).setjavascriptenabledtrue mwebview01.requestfocus /* 產生 html 語法 */ forint i=0;i<sphoto.length;i++) data+="<img class=\"pic\" style=\"z-index:"+indx[i]+ ";-webkit-transform:rotate"+rotate[i]+"deg\" "+ "src=\"file:///android_asset/image/"+sphoto[i]+ "\" width=\"75\" height=\"75\" alt=\""+name[i]+"\"/>"; /* 載入放在 assets 裡的網頁 */ mwebview01.loadurlhtmlpath mwebview01.setwebviewclientnew WebViewClient) 10 Android 1279
public void onpagefinishedwebview view, String url) /* 動態將顯示相片的 HTML 語法加入頁面中 */ mwebview01.loadurl "javascript:document.getelementbyid'mycontent'). innerhtml='"+data+"'" super.onpagefinishedview, url /assets/gallery.html gallery.html 為一般乾淨的 HTML 網頁, 檢視原始碼沒有任何 CSS 的標籤定義, 唯一要置換的是圖層 ID mycontent 裡的網頁內容 <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <style type="text/css"> * margin: 0; padding: 0; border: 0; body background: #123456; text-align:center; #container width:300px; margin: 0px auto; h1 font: bold 35px/30px Helvetica, Arial, Sans-serif; text-align: center; color: #eee; text-shadow: 0px 2px 6px #333; div.gallery list-style: none; text-align:center; div.gallery.pic position: relative; float: left; 1280 Google Android SDK 3