Android 應用程式開發:處理更多的相機功能

在 Android 應用程式中,撰寫程式碼存取內建照相機、預覽結果、儲存成影像,算是基本功,但是現代智慧型手機通常擁有具備眾多功能的複雜照相機,這些功能包括閃光燈、白平衡、各種場景模式、不同的 Instagram 風格相片效果,甚至是人臉偵測。看看 Camera.Parameters API 文件即可得知有哪些功能。Camera.Parameters API 還可以讓你查看執行應用程式的硬體,究竟支援了哪些功能。一旦你知道有哪些參數、功能可用,它們的使用方式都大同小異,接著就讓我們看看如何使用它們。

處理閃光燈

讓我們先從閃光燈開始,這可能是最常用到的相機功能。我們將設計一個 chooseFlash() 方法來設定閃光燈選項:

private void chooseFlash() {
  final Camera.Parameters params = camera.getParameters();
  final List<String />flashModeList = params.getSupportedFlashModes();
  if (flashModeList == null) {
    // no flash!
    return;
  }
  final CharSequence[] flashText = flashModeList.toArray(
                                 new CharSequence[flashModeList.size()]);
  AlertDialog.Builder builder = new AlertDialog.Builder(this);
  builder.setTitle("Choose flash type");
  builder.setSingleChoiceItems(flashText, -1,
                               new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
      params.setFlashMode(flashModeList.get(which));
      camera.setParameters(params);
      dialog.dismiss();
    }
  });
  final AlertDialog alert = builder.create();
  alert.show();
}

在開始之前,我們需要透過 getSupportedFlashModes(),檢查一下有哪些閃光燈模式可用。如果列表是空的,表示沒有閃光燈,我們就直接回傳。

如果有閃光燈模式,我們讓用戶自己從中選擇一個。我們用 AlertDialog 來處理,不過你也可以用其他方式。我們把閃光燈模式(字串形式)的列表,轉成 CharSequence 陣列傳給 AlertDialog.Builder,接著用 Builder 的方法設定標題並加入單選按鈕選項(用 setSingleChoiceItems(),你也可以用複選方塊,或用 setItems() 建立可選清單)。

使用者選擇偏好的閃光燈模式後,我們用對話框的 OnClickListener 來找出選定項目的索引值,將其從 flashModeList 字串列表中取出以設定參數。因為我們是直接把 flashModeList 轉成 AlertDialog 所用的 CharSequence 陣列,AlertDialog 中的選定項目索引值,和該項目在 flashModeList 中的索引值是相同的。

你得在 params.setFlashMode() 之後呼叫 camera.setParameters(),以便讓選擇生效。之後我們解除對話框以結束 onClick() 方法,並回到主畫面。最後,在建立該對話框後,我們產生該對話框並加以顯示。

動態佈局

接下來的問題是如何顯示給用戶看。我們可以在應用程式啓動時自動執行,不過這樣做對使用者不太有親和力。我們可以在靜態佈局中加入一些 XML,但是當裝置沒有閃光燈時,還是會顯示出來,這樣一來就浪費了顯示空間且用戶親和性會大打折扣。取而代之,我們可以用動態佈局,也就是依據程式中所發生的事件來管理佈局。

為此,取代 alert.show() 這行,我們在 chooseFlash() 方法結尾加入這些程式碼,好讓我們在按鈕點選時才顯示閃光燈選項列表。

LinearLayout lin = (LinearLayout) findViewById(R.id.linearlayout);
Button flashButton = new Button(this);
flashButton.setText("Flash");
flashButton.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                            LayoutParams.WRAP_CONTENT));
lin.addView(flashButton);
flashButton.setOnClickListener(
  new View.OnClickListener() {
    public void onClick(View v) {
      alert.show();
    }
  }
);

在你的 XML 中,你還得為上層的 LinearLayout 加入 ID 值。

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/linearlayout"
  ... >

這段程式碼會取得上層 LinearLayout 的參照,建立 Flash 按鈕並將其加入佈局中,接著在按鈕按下時顯示 AlertDialog。正如你所見,按鈕的高與寬可以經由 setLayoutParams() 加以程式化設定。這些參數是 ViewGroup.LayoutParams,其中有許多建構子 (constructors) 可用,這裡用到的這一個負責寬與高。你可以使用 LayoutParams 的子類別,以便更為具體地建構佈局。按鈕的其他屬性全都可以程式化設定。例如,你可能希望用 setBackgroundDrawable() 取代 setText(),讓按鈕顯示圖像而非文字 (或者改用 ImageButton 與 setImageResource())。

最後,我們將程式碼掛載到 setUpLayout() 方法:

private void setUpLayout() {
  // ... as before
  chooseFlash();
}

編譯並在你的手機上測試看看。

場景設定

Android 提供了不少的相機效果,當然硬體支援度依照個別手機有所差異。這些功能包括縮放、antibanding、場景模式、對焦模式等。可查閱 Camera Parameter 文件以獲得完整列表。不過它們的設定與處理方式都很類似,因此讓我們很快地來看另一個例子,場景模式設定。這些模式包括派對、人像、風景、夜景等,詳情請見 getSceneMode() 文件。實際的列表依你的相機類型有所不同。

private void chooseSceneMode() {
  final Camera.Parameters params = camera.getParameters();
  final List<String />sceneModeList = params.getSupportedSceneModes();
  if (sceneModeList == null) {
    // no scene mode available!
    return;
  }
  final CharSequence[] sceneModeText = sceneModeList.toArray(
                                 new CharSequence[sceneModeList.size()]);
  AlertDialog.Builder builder = new AlertDialog.Builder(this);
  builder.setTitle("Choose scene mode");
  builder.setSingleChoiceItems(sceneModeText, -1,
                               new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
      params.setSceneMode(sceneModeList.get(which));
      camera.setParameters(params);
      dialog.dismiss();
    }
  });
  final AlertDialog alert = builder.create();
  LinearLayout lin = (LinearLayout) findViewById(R.id.linearlayout);
  Button sceneModeButton = new Button(this);
  sceneModeButton.setText("Scene Mode");
  sceneModeButton.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                            LayoutParams.WRAP_CONTENT));
  lin.addView(sceneModeButton);
  sceneModeButton.setOnClickListener(
    new View.OnClickListener() {
      public void onClick(View v) {
        alert.show();
      }
    }
  );
}

如你所見,基本上這跟 chooseFlash() 是一樣的,正因如此,比較好的做法是,將其重構為 chooseEffect() 方法,然後把你要設定的效果類型當成參數傳遞進去。這是個不錯的練習,可以看看你還可以使用哪些效果。

你或許還希望改進其佈局,目前的佈局在視覺上不太賞心悅目,尤其當更多按鈕與效果加入之後。例如說,你可能想加入滑動選單,或把按鈕排成一排。


原文網址:https://www.linux.com/learn/tutorials/731988-android-app-development-handling-extra-camera-capabilities/



您也許有興趣閱讀以下文章:




自由軟體鑄造場電子報 : 第 226 期 Android 應用程式開發:處理更多的相機功能

分類: 技術專欄