ValueAnimator(好用的動畫類別)


這裡介紹簡單又好用的動畫類別 ValueAnimator ,有時候我們想做些簡單的過場動畫或是特別按鍵動畫,遊戲的實現上相當簡單,以分工而言,程式設計師基本上只要負責影格的播放即可,其他的部分都交給視覺人員來完成,但在應用程式上,各部份元件(按鈕,清單,佈局等等)就沒有影格來達到特別的動畫呈現,此時 ValueAnimator 就能達到我們的需求,先給個簡單的範例如下

   1:  ValueAnimator fadein = ObjectAnimator.ofFloat(button, "alpha", 0f, 1f);
   2:  fadein.setDuration(4000);
   3:  fadein.start();

第 1 行建立 ValueAnimator 物件 fadein , ObjectAnimator 是其子類別,這裡使用多型建立 fadein 第 1 個參數為動畫的目標,第 2 個參數為改變的特性, 第 3 個參數為起始的數值, 第 4 個參數為結束的數值
第 2 行設定動畫時間,為 4 秒
第 3 行執行動畫

簡單的 3 行就能達到淡入的效果,當然還有其它的動畫種類能選擇,如放大縮小(scale),旋轉(rotation)等等,開始執行動畫後如果需要取得動畫結束,取消等等的狀態,這時候就需要加入 AnimatorListener 來偵測,如下

   1:          ValueAnimator fadein = ObjectAnimator.ofFloat(logoView, "alpha", 0f, 1f);
   2:          fadein.setDuration(5000);
   3:          fadein.addListener(new AnimatorListener() {
   4:              
   5:              @Override
   6:              public void onAnimationStart(Animator animation) {
   7:                  // TODO Auto-generated method stub
   8:                  
   9:              }
  10:              
  11:              @Override
  12:              public void onAnimationRepeat(Animator animation) {
  13:                  // TODO Auto-generated method stub
  14:                  
  15:              }
  16:              
  17:              @Override
  18:              public void onAnimationEnd(Animator animation) {
  19:                  // TODO Auto-generated method stub
  20:                  //動畫結束後要做的事寫在這
  21:              }
  22:              
  23:              @Override
  24:              public void onAnimationCancel(Animator animation) {
  25:                  // TODO Auto-generated method stub
  26:                  
  27:              }
  28:          });

第 3 行加入監聽器之後就能知道甚麼時候動畫結束,也可以同時或依序來執行多種動畫,這時候建議使用 AnimatorSet 來搭配使用,以下是 1 個 2 秒淡入,2秒靜止,2秒淡出的動畫範例

   1:          ValueAnimator fadein = ObjectAnimator.ofFloat(logoView, "alpha", 0f, 1f);
   2:          fadein.setDuration(2000);
   3:          
   4:          ValueAnimator standby = ObjectAnimator.ofFloat(logoView, "alpha", 1f, 1f);
   5:          standby.setDuration(2000);
   6:          
   7:          ValueAnimator fadeout = ObjectAnimator.ofFloat(logoView, "alpha", 1f, 0f);
   8:          fadeout.setDuration(2000);
   9:          
  10:          AnimatorSet bouncer = new AnimatorSet();
  11:          bouncer.playSequentially(fadein,standby,fadeout);
  12:          bouncer.start();

和上述的範例一樣,先建立 3 段動畫
第 10 行建立 AnimatorSet 物件
第 11 行使用依序播放,參數順序代表播放順序
第 12 行播放

同時播放動畫的範例如下

   1:                  ValueAnimator rotationY = ObjectAnimator.ofFloat(bYes, "rotationY", 0f, 360f);
   2:                  ValueAnimator rotationX = ObjectAnimator.ofFloat(bYes, "rotationX", 0f, 360f);
   3:                  rotationY.setDuration(1000);                
   4:                  rotationX.setDuration(500);
   5:                 
   6:                  AnimatorSet as = new AnimatorSet();
   7:                  as.playTogether(rotationY,rotationX);
   8:                  as.start();

只要修改 playSequentially 為 playTogether 就OK囉,上面的範例可以用在按鍵的特效, AnimatorSet 也可以參雜使用如下

   1:          ValueAnimator rotationY = ObjectAnimator.ofFloat(logoView, "rotationY", 0f, 360f);
   2:          ValueAnimator rotationX = ObjectAnimator.ofFloat(logoView, "rotationX", 0f, 360f);
   3:          rotationY.setDuration(5000);                
   4:          rotationX.setDuration(2500);
   5:          
   6:          AnimatorSet scalexy = new AnimatorSet();
   7:          scalexy.playTogether(rotationY,rotationX);
   8:          
   9:          
  10:          ValueAnimator standby = ObjectAnimator.ofFloat(logoView, "alpha", 1f, 1f);
  11:          standby.setDuration(1000);
  12:          
  13:          ValueAnimator fadeout = ObjectAnimator.ofFloat(logoView, "alpha", 1f, 0f);
  14:          fadeout.setDuration(2000);
  15:          
  16:          AnimatorSet bouncer = new AnimatorSet();
  17:          bouncer.playSequentially(scalexy,standby,fadeout);
  18:          
  19:          bouncer.start();

第 1 ~ 7行為第 1 個 AnimatorSet ,動畫內容為同時旋轉X,Y軸
第 10 ~ 16行為第 2 個 AnimatorSet ,動畫內容為播放第 1 個 AnimatorSet 後,再播放靜止和淡出

只要使用上述的技巧就能組合出自己想要的動畫,不只如此,在每個動畫中還能設定反轉,重複播放,動畫播放速度的細節,以及加速器,減速器,線性加速器等等,相當好用~~

結果為
Logo翻轉中
















access to class not allowed


想要啟動某個 Activity ,除了在 AndroidManifest.xml 中設定外,還必須注意其存取修飾詞為 public ,當然在系統預設情況下為 public,但手動加入 Activity 時就要注意了,如果不是 public ,會出現 access to class not allowed 的例外,如下圖


解決方法就修改存取修飾詞為 public 吧

Logo流程(Activity+Handler+Message)


本篇實作簡單的 Logo 流程,慢慢的淡入顯示 Logo 圖示再切換到版權聲明流程,加入 Thread, Message , Handler 類別以控制 Thread 和 Activity 之間的通訊,在 Android 中基於安全性的考量,不予許非主執行緒更改主畫面的元件,一旦違反這個規則,會出現


的例外,所以我們必須考慮使用其他類別搭配達到計時改變的效果,首先準備一張代表 Logo 的圖示,並放入 res -> drawable 資料夾中(記得圖名不可使用英文大寫),接著我們使用 RelativeLayout 並加入 1 個 ImageView 元件,其內容如下


   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   3:      android:layout_width="match_parent"
   4:      android:layout_height="match_parent" >
   5:   
   6:      <ImageView
   7:          android:id="@+id/imageView1"
   8:          android:layout_width="fill_parent"
   9:          android:layout_height="fill_parent"
  10:          android:layout_alignParentLeft="true"
  11:          android:layout_alignParentTop="true"
  12:          android:src="@drawable/yellow_logo" />
  13:   
  14:  </RelativeLayout>

第 6 行為 ImageView 元件的開頭
第 7 行為其 id
第 8 ~ 9 行代表即使 ImageView 會填滿父元件
第 10 ~ 11 行對齊父元件的左上方
第 12 行為其資源的來源

接著來看看 Logo 流程的程式碼


LogoFlow.java

   1:  package com.example.helloworld;
   2:   
   3:  import android.annotation.SuppressLint;
   4:  import android.app.Activity;
   5:  import android.content.Intent;
   6:  import android.os.Bundle;
   7:  import android.os.Handler;
   8:  import android.os.Message;
   9:  import android.util.Log;
  10:  import android.widget.ImageView;
  11:   
  12:  @SuppressLint("NewApi")
  13:  public class LogoFlow extends Activity implements Runnable{
  14:   
  15:      ImageView logoView;
  16:      
  17:      Handler handler;
  18:      
  19:      float logoActIndex;
  20:      
  21:      boolean sleeping;
  22:      
  23:      public void onCreate(Bundle savedInstanceState){
  24:          
  25:          super.onCreate(savedInstanceState);
  26:          
  27:          setContentView(R.layout.logoflow);
  28:          
  29:          logoView = (ImageView)findViewById(R.id.imageView1);
  30:          
  31:          logoView.setAlpha(0.0f);
  32:          
  33:          handler = new Handler(){
  34:              
  35:              public void handleMessage(Message msg) {
  36:   
  37:                  Log.v("Trace Log", "revice maessage");
  38:                  
  39:                  if(logoView.getAlpha()<1.0f){
  40:                      logoActIndex+=0.01f;
  41:                      logoView.setAlpha(logoActIndex);
  42:                      Log.v("Trace Log", "test2");
  43:                  }
  44:                  else if(logoView.getAlpha()>=1.0f){
  45:                      
  46:                      LogoFlow.this.finish(); // close activity
  47:                      
  48:                      Log.v("Trace Log", "test3");
  49:                      sleeping = true;// stop Thread
  50:   
  51:                      Intent goAct = new Intent();// new a Intent
  52:                      goAct.setClass(LogoFlow.this, CopyRightFlow.class); // set another activity
  53:                      startActivity(goAct); // start another Activity
  54:                      
  55:                      System.exit(0);// stop program
  56:   
  57:                  }
  58:                  
  59:                  Log.v("Trace Log", ""+logoView.getAlpha());
  60:                  
  61:                  super.handleMessage(msg);
  62:   
  63:              }
  64:              
  65:          };
  66:          
  67:          Thread th = new Thread(this);
  68:          th.start();
  69:      }
  70:      
  71:      public void run() {
  72:          // TODO Auto-generated method stub
  73:          
  74:          while(!sleeping){
  75:              
  76:              try {
  77:                  Thread.sleep(30);
  78:              } catch (InterruptedException e) {
  79:                  // TODO Auto-generated catch block
  80:                  e.printStackTrace();
  81:              }
  82:              
  83:              Message m = new Message();
  84:              
  85:              handler.sendMessage(m);
  86:              
  87:          }
  88:      }
  89:  }

第 13 行 implements Runnable 介面,目的是建立計時器,必須實作其 run 方法(第 71 行)
第 15 行就是 Logo 圖示,待會讓它慢慢淡出
第 17 行 Handler 類別的物件,負責接收 Message 的發送,你可以把它當作接收器,就如同 Activity 的 onTouchEvent( ) 方法會自動接收觸碰的事件
第 19 行控制 logoView 的淡入程度
第 21 行控制執行緒的進行
第 27 行套用上述的佈局檔
第 29 行建立 logoView 物件
第 31 行設定 logoView 的 alpha 值, 0 代表看不見
第 33 ~ 65 行建立 handler 物件, 必須覆寫其 handleMessage( )方法,並在其中加入欲實行的動作
第 39 ~ 43 行為慢慢顯示 logoView 物件的動作
第 44 ~ 57 行為結束該 Activity 的動作,注意第 46,49,55 行,當使用多執行緒並在多 Activity 切換時有可能造成 activity 和 thread 不同步的情況,解決的步驟為 1.先把目前的 Activity 關閉(46行) 2.停止執行緒的進行(49行) 3.使用Intent 開啟新的 Activity (51~53行) 4.使用 System.exit() 結束
第 61 行呼叫父類別的 handleMessage()方法
第 67 ~ 68 行啟動 Thread
第 71 ~ 88 行為覆寫 run () 方法, 在每一次的迴圈中都會建立 Message 物件並傳送訊息,訊息發送後就會被 Handler 的 handleMessage () 方法自動接收,達到計時改變狀態的效果

結果為
開始執行

















2秒後

















跳入下一流程(版權聲明流程)

Failed to install xxx.apk on device 'xxx': timeout


通常發生於太久時間沒有操作手機,解決方法直接拔 usb 線,重插








警告提示(AlertDialog)

AlertDialog 就是警告提示,通常用在訊息的提示,比如說離開程序前,進行動作前等等,通常都會搭配按鈕讓使用者選擇,可以把它當作進階版的 Toast 視窗來使用,基本建構子如下,第1個參數為 context

ps: 參數context,必須是activity的context,不可為getApplicationContext()的Context,否則會出現
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application...的例外


AlertDialog ad = new AlertDialog.Builder(this).create();

API 11還有4種話框主題可以選擇,使用建構子的第2個參數來指定主題,另外第2個參數也可以使用 xml 來指定,ex: R.layout.xxx

        AlertDialog ad = new AlertDialog.Builder(this,AlertDialog.THEME_DEVICE_DEFAULT_DARK).create();
        AlertDialog ad = new AlertDialog.Builder(this,AlertDialog.THEME_DEVICE_DEFAULT_LIGHT).create();
        AlertDialog ad = new AlertDialog.Builder(this,AlertDialog.THEME_HOLO_DARK).create();
        AlertDialog ad = new AlertDialog.Builder(this,AlertDialog.THEME_HOLO_LIGHT).create();
        AlertDialog ad = new AlertDialog.Builder(this,AlertDialog.THEME_TRADITIONAL).create();

其他較常用方法如下

        ad.setTitle("標題");//設定警告標題
        ad.setMessage("訊息");//設定警告內容
        ad.setButton("按鈕1", new DialogInterface.OnClickListener() {//設定按鈕1
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                
                //點選按鈕1後執行的動作
            }
        });
        ad.setButton2("按鈕2", new DialogInterface.OnClickListener() {//設定按鈕2
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                
                //點選按鈕2後執行的動作
            }
        });
        ad.setButton3("按鈕3", new DialogInterface.OnClickListener() {//設定按鈕3
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                
                //點選按鈕3後執行的動作
            }
        });
        
        ad.setCanceledOnTouchOutside(false);//當警告提示出現後,點選提示以外範圍,是否會取消提示,預設是true
        
        ad.setCancelable(false);//當警告提示出現後,點選其他實體按鈕(backkey等等),是否會取消提示,預設是true
        
        ad.show();//顯示按鈕

結果為


















在版權聲明流程中,點選離開後加入1個警告提示,程式碼如下

   1:  void showAlertDialog(){
   2:   
   3:          AlertDialog ad = new AlertDialog.Builder(this).create();
   4:          
   5:          ad.setTitle("警告");//設定警告標題
   6:          ad.setMessage("確定離開??");//設定警告內容
   7:          ad.setButton("確定", new DialogInterface.OnClickListener() {//設定按鈕1
   8:              
   9:              @Override
  10:              public void onClick(DialogInterface dialog, int which) {
  11:                  
  12:                  //點選按鈕1後執行的動作
  13:                  //檢查網路狀態
  14:                  ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  15:   
  16:                  NetworkInfo ni = cm.getActiveNetworkInfo();
  17:                  if (ni != null && ni.isConnected()) {//若有網路先連結到外部網頁
  18:   
  19:                      Uri uri = Uri.parse("http://vulpesadn.blogspot.tw/");
  20:                      Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  21:                      startActivity(intent);
  22:   
  23:                      finish();//再結束程序
  24:                  } else if (ni == null) {//沒有網路
  25:   
  26:                      finish();//結束程式
  27:                  }
  28:              }
  29:          });
  30:          ad.setButton2("取消", new DialogInterface.OnClickListener() {//設定按鈕2
  31:              
  32:              @Override
  33:              public void onClick(DialogInterface dialog, int which) {
  34:                  
  35:                  //點選按鈕2後執行的動作
  36:                  //無動作
  37:              }
  38:          });
  39:          
  40:          ad.setCanceledOnTouchOutside(false);//當警告提示出現後,點選提示以外範圍,是否會取消提示,預設是true
  41:          
  42:          ad.setCancelable(false);//當警告提示出現後,點選其他實體按鈕(backkey等等),是否會取消提示,預設是true
  43:          
  44:          ad.show();//顯示按鈕
  45:      }


結果為




設定視窗相關(全螢幕,去title,指定方向)


很多程序在運行時都會把視窗最大化(全螢幕)且去掉 title,尤其是遊戲,這樣除了可以避免不必要的觸碰之外還能讓視覺上有比較好的範圍,全螢幕必須由 Window 類別達成,如下
   1:  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

事實上是等於這樣
   1:  Window w = getWindow();
   2:  w.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
當然 setFlags() 還有很多參數可以設定,參考這裡

去掉 Title 可使用 Activity 的 requestWindowFeature( ) 完成,如下
   1:  requestWindowFeature(Window.FEATURE_NO_TITLE);

指定視窗方向也是很常使用的方法,一般手機的預設都是自動旋轉,在某些情況下我們必須固定視窗方向,舉例來說橫軸射擊遊戲不會讓你旋轉畫面,方法如下

   1:  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
   2:  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

第 1 行為固定直式視窗畫面
第 2 行為固定橫式視窗畫面
必須注意的是如果程序會啟動不同的 Activity ,那在每個 Activity 的 onCreate() 都必須寫入設定,以上是用程式碼來達成,缺點是在啟動程序時還是會先顯示狀態列,我們可以改在 AndroidManifest.xml 中加入屬性這樣在啟動時就不會顯示狀態列了,如
去掉 title bar + 全螢幕

   1:  android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"

指定視窗方向

   1:  android:screenOrientation="portrait"
要注意這2個屬性必須在 <activity> 標籤內使用,如
   1:  <activity
   2:              android:name=".CopyRightFlow"
   3:              android:label="@string/title_activity_main" 
   4:              android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"
   5:              android:screenOrientation="portrait">
   6:              
   7:              <intent-filter>
   8:                  <action android:name="android.intent.action.MAIN" />
   9:   
  10:                  <category android:name="android.intent.category.LAUNCHER" />
  11:              </intent-filter>
  12:              
  13:          </activity>


將之前的版權宣告流程修改為全螢幕,去Title,程式碼為

   1:  package com.example.helloworld;
   2:   
   3:  import android.app.Activity;
   4:  import android.content.Context;
   5:  import android.content.Intent;
   6:  import android.content.pm.ActivityInfo;
   7:  import android.graphics.Typeface;
   8:  import android.net.ConnectivityManager;
   9:  import android.net.NetworkInfo;
  10:  import android.net.Uri;
  11:  import android.os.Bundle;
  12:  import android.view.Gravity;
  13:  import android.view.View;
  14:  import android.view.View.OnClickListener;
  15:  import android.view.Window;
  16:  import android.view.WindowManager;
  17:  import android.widget.Button;
  18:  import android.widget.TextView;
  19:   
  20:  public class MainActivity extends Activity {
  21:   
  22:      static final String tLog = "Trace Log";
  23:   
  24:      TextView tv; // init by xml use
  25:   
  26:      Button bYes; // enter button
  27:      Button bNo; // exit button
  28:      
  29:      @Override
  30:      public void onCreate(Bundle savedInstanceState) {
  31:   
  32:          super.onCreate(savedInstanceState);
  33:          
  34:          setWindowFeature();
  35:          
  36:          initByXml();
  37:   
  38:      }
  39:      
  40:      void setWindowFeature(){
  41:          //fullscreen
  42:          getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
  43:          //no title
  44:          requestWindowFeature(Window.FEATURE_NO_TITLE);
  45:          //portrait
  46:          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  47:      }

47行之後都是相同的,注意第 34 行 setWindowFeature() 方法就是本篇介紹的方法,你必須放在 super.onCreate()之後

結果為


















取得手機基本資訊(SDK,手機名稱,製造商名稱...)


Android 手機上的基本硬體資訊可由 android.os 套件中提供的類別來取得,其中的 android.os.Build 類別可取得相當多的資訊,如主機板,手機名稱,內部識別碼等等,相關範例如下

   1:          Log.v(tLog,""+Build.VERSION.SDK_INT); // phone SDK version
   2:          Log.v(tLog,""+Build.MODEL); // phone name
   3:          Log.v(tLog,""+Build.MANUFACTURER); // phone manufacturer
   4:          Log.v(tLog,""+Build.BOARD); // phone mother board 
   5:          Log.v(tLog,""+Build.BRAND); // phone brand

第 1 行取得手機上目前 Android SDK Version
第 2 行取得手機名稱,如 HTC Incredible S
第 3 行取得製造商名稱,如 HTC
第 4 行取得手機的主機板名稱,如 vivo
第 5 行取得手機的品牌名稱,如 twn_tw


振動功能


振動功能可藉由 Vibrator 類別完成, Vibrator是相當單純的類別,直接繼承 java.lang.Object,本身也沒有任何子類別,使用方法非常簡單,不過還是需要許可才行,在 AndroidManifest.xml 加入以下許可


<uses-permission android:name="android.permission.VIBRATE" />


接著藉由 Context 類別的 getSystemService 方法建立 Vibrator 類別的物件,如下

   1:  Vibrator vi = (Vibrator)getSystemService(VIBRATOR_SERVICE);

第 1行  (Vibrator)getSystemService(VIBRATOR_SERVICE); 是 Context 的方法,回傳值為 object , 所以要轉型為 Vibrator

而 Vibrator 類別提供的方法也很簡單

   1:  if(vi.hasVibrator()){ // check vibrate exist(API 11)
   2:      vi.vibrate(5000); // start vibrate
                
     }

第 1 行檢查是否有震動功能, API 11 才有這個方法
第 2 行開始震動,參數為 Milliseconds

開啟網頁 + 檢查網路狀態


開啟網頁可用 Uri 搭配 Intent 來達成 , 如下
   1:  Uri uri = Uri.parse("http://vulpesadn.blogspot.tw/");
   2:  Intent intent = new Intent(Intent.ACTION_VIEW, uri);
   3:  startActivity(intent);


還要記得在 AndroidManifest.xml 加入網路許可
<uses-permission android:name="android.permission.INTERNET" />

開啟網頁在很多情況都會使用到,如離開程序之後強制連到官網, 或是在程序中有更多商品的選項時,都會直接連結到官網中,當然我們也能在連網之前先檢查網路狀態,在沒有連線的情況就能直接離開程序而不連到官網了

檢查網路狀態,必須加入存取網路許可
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

接著使用 ConnectivityManager 來取得 NetworkInfo 的 isConnected( ) 來取得連網狀態,如下
   1:  ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
   2:   
   3:  NetworkInfo ni = cm.getActiveNetworkInfo();
   4:  if (ni != null && ni.isConnected()) {
   5:   
   6:              Uri uri = Uri.parse("http://vulpesadn.blogspot.tw/");
   7:              Intent intent = new Intent(Intent.ACTION_VIEW, uri);
   8:              startActivity(intent);
   9:   
  10:  } else if (ni == null) {
  11:   
  12:              finish(); // exit program
  13:  }


第 1 行建立 ConnectivityManager cm 來取得連網狀態, getSystemService 為 Context 類別的方法
第 3 行取得 NetworkInfo ni 來判斷 ni 的狀態
第 4 行注意除了 ni.isConnected() 的判斷之外還要小心 ni 是否為 null
第 6 ~ 8 行就是開啟網頁的方法了
第 10 行若 ni == null 就離開程序

我把上述做法加到版權聲明的流程,整體程式碼如下
   1:  package com.example.helloworld;
   2:   
   3:  import android.app.Activity;
   4:  import android.content.Context;
   5:  import android.content.Intent;
   6:  import android.graphics.Typeface;
   7:  import android.net.ConnectivityManager;
   8:  import android.net.NetworkInfo;
   9:  import android.net.Uri;
  10:  import android.os.Bundle;
  11:  import android.view.Gravity;
  12:  import android.view.View;
  13:  import android.view.View.OnClickListener;
  14:  import android.webkit.WebView;
  15:  import android.widget.Button;
  16:  import android.widget.TextView;
  17:  import android.widget.Toast;
  18:   
  19:  public class MainActivity extends Activity {
  20:   
  21:      static final String tLog = "Trace Log";
  22:   
  23:      TextView tv; // init by xml use
  24:   
  25:      Button bYes; // enter button
  26:      Button bNo; // exit button
  27:   
  28:      @Override
  29:      public void onCreate(Bundle savedInstanceState) {
  30:   
  31:          super.onCreate(savedInstanceState);
  32:   
  33:          initByXml();
  34:   
  35:      }
  36:   
  37:      void initByXml() {
  38:          setContentView(R.layout.activity_main);
  39:          // TextView init
  40:          tv = (TextView) findViewById(R.id.textView1);// why can't cast to
  41:                                                          // TestTextView
  42:          tv.setTextColor(0xff888888); // set color
  43:          tv.setTextSize(18.0f); // set size
  44:          tv.setTypeface(Typeface.SERIF);// set typeface
  45:          tv.setText(R.string.copy_right);// change text
  46:          tv.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
  47:   
  48:          // ButtonYes init
  49:          bYes = (Button) findViewById(R.id.buttonYes); // get ButtonYes
  50:          OnClickListener bYesOc = new OnClickListener() { // build ButtonYes Listener
  51:   
  52:              @Override
  53:              public void onClick(View v) {
  54:                  // TODO Auto-generated method stub
  55:   
  56:                  Intent goAct = new Intent();// new a Intent
  57:                  goAct.setClass(MainActivity.this, GetDisplaySize.class); // set class
  58:                  startActivity(goAct); // start another Activity
  59:                  finish(); // exit program
  60:                  
  61:              }
  62:          };
  63:          bYes.setOnClickListener(bYesOc);// set ButtonYes Listener
  64:   
  65:          // ButtonNo init
  66:          bNo = (Button) findViewById(R.id.buttonNo); // get ButtonNo
  67:          bNo.setOnClickListener(new OnClickListener() { // build ButtonNo Listener
  68:   
  69:              @Override
  70:              public void onClick(View v) {
  71:                  // TODO Auto-generated method stub
  72:                  
  73:                  ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  74:   
  75:                  NetworkInfo ni = cm.getActiveNetworkInfo();
  76:                  if (ni != null && ni.isConnected()) {
  77:   
  78:                      Uri uri = Uri.parse("http://vulpesadn.blogspot.tw/");
  79:                      Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  80:                      startActivity(intent);
  81:                      finish(); // exit program
  82:                  } else if (ni == null) {
  83:   
  84:                      finish(); // exit program
  85:                  }
  86:              }
  87:          });
  88:      }
  89:  }


結果為
在開啟網路的情況下按下離開會直接連到我的部落格


















沒有開啟網路的情況,就離開程序囉


















NetworkInfo 還能取得更多關於連網的詳細資料,如是否漫遊,連網的詳細資訊等等,不過離開程序後強制連到官網的做法有待商榷,畢竟這並不是好的方式,很容易造成使用者的反感!! 慎行!!






按鈕 + 結束程序 + 啟動新 Activity


在 Android 中按鈕的產生和操作是由 Button 類別來實作, Button 可由 xml 事先定義好的方式產生,也可以在程式碼中直接建立,建立完成後必須寫出該按鈕的監聽器,並在監聽器中寫入特定方法,修改 MainActivity.java ,加入按鈕如下

MainActivity.java

   1:  package com.example.helloworld;
   2:   
   3:  import android.app.Activity;
   4:  import android.content.Context;
   5:  import android.content.Intent;
   6:  import android.graphics.Typeface;
   7:  import android.os.Bundle;
   8:  import android.view.Gravity;
   9:  import android.view.View;
  10:  import android.view.View.OnClickListener;
  11:  import android.widget.Button;
  12:  import android.widget.TextView;
  13:   
  14:  public class MainActivity extends Activity {
  15:   
  16:      static final String tLog = "Trace Log";
  17:   
  18:      TextView tv; // init by xml use
  19:   
  20:      Button bYes; // enter button
  21:      Button bNo; // exit button
  22:   
  23:      @Override
  24:      public void onCreate(Bundle savedInstanceState) {
  25:   
  26:          super.onCreate(savedInstanceState);
  27:   
  28:          initByXml();
  29:   
  30:      }
  31:   
  32:      void initByXml() {
  33:          setContentView(R.layout.activity_main);
  34:          // TextView init
  35:          tv = (TextView) findViewById(R.id.textView1);// why can't cast to
  36:                                                          // TestTextView
  37:          tv.setTextColor(0xff888888); // set color
  38:          tv.setTextSize(18.0f); // set size
  39:          tv.setTypeface(Typeface.SERIF);// set typeface
  40:          tv.setText(R.string.copy_right);// change text
  41:          tv.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
  42:   
  43:          // ButtonYes init
  44:          bYes = (Button) findViewById(R.id.buttonYes); // get ButtonYes
  45:          OnClickListener bYesOc = new OnClickListener() { // build ButtonYes Listener
  46:   
  47:              @Override
  48:              public void onClick(View v) {
  49:                  // TODO Auto-generated method stub
  50:   
  51:                  Intent goAct = new Intent();// new a Intent
  52:                  goAct.setClass(MainActivity.this, GetDisplaySize.class); // set class
  53:                  startActivity(goAct); // start another Activity
  54:                  finish(); // exit program
  55:              }
  56:          };
  57:          bYes.setOnClickListener(bYesOc);// set ButtonYes Listener
  58:   
  59:          // ButtonNo init
  60:          bNo = (Button) findViewById(R.id.buttonNo); // get ButtonNo
  61:          bNo.setOnClickListener(new OnClickListener() { // build ButtonNo Listener
  62:   
  63:              @Override
  64:              public void onClick(View v) {
  65:                  // TODO Auto-generated method stub
  66:   
  67:                  finish(); // exit program
  68:   
  69:              }
  70:          });
  71:   
  72:      }
  73:   
  74:  }


第 20 ~ 21 行為加入的按鈕,其詳細定義在 xml 中, 由於 MainActivity.java 會修改為版權宣告流程, 當繼續 (bYes) 按鈕按下,就會進入下一個流程, 而離開(bNo)按鈕按下,就會離開程序
第 28 行 initByXml(); 為初始化的動作,在該流程中需要的元件都會在這初始化
第 33 行套用 R.layout.activity_main 的佈局
第 35 ~ 41 行為 TextView 的使用,其內容( R.string.copy_right )為版權聲明
第 44 行取得在佈局中的按鈕(R.id.buttonYes),並指定給 bYes
第 45 行使用匿名內部類別建立 bYesOc 監聽器
第 48 行覆寫 onClick(View v) 方法,並在其中加入按下按鈕觸發的事件
第 51 行建立 Intent goAct = new Intent(); 用來啟動另 1 個 Activity
第 52 行 goAct.setClass(MainActivity.this, GetDisplaySize.class);  第1個參數為當前的 Activity而第 2 個參數為想啟動的 Activity
第 53 行啟動 Activity
第 54 行結束目前的 Activity
第 57 行讓 bYes 按鈕套用 bYesOc 監聽器內容    
第 60 ~ 70 行為 bNo 按鈕的設定
第 61 行直接在 setOnClickListener 方法中建立監聽器
第 67 行結束程序,這種結束程序是指關閉 Activity ,如果有多 Activity 在執行或切換時,建議使用 System.exit( ) 方法

結果為


















按了繼續之後,跳到 GetDisplaySize 類別


















按了離開之後,結束程序回到桌面




















Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Affiliate Network Reviews