導入預覽

在應用程式中新增預覽時,請使用 PreviewView。這種 View 可供裁剪、縮放及旋轉,以便正確顯示圖片。

當相機啟動時,圖片預覽會串流至 PreviewView 內部途徑。

使用 PreviewView

使用 PreviewView 對 CameraX 導入預覽的過程包含下列步驟,詳情請見後續章節:

  1. (選用) 設定 CameraXConfig.Provider
  2. 在版面配置中加入 PreviewView
  3. 要求 ProcessCameraProvider
  4. 建立 View 時確認 ProcessCameraProvider
  5. 選取相機並繫結至生命週期和用途。

使用 PreviewView 有些許限制。使用 PreviewView 時,您將無法執行下列任一操作:

  • 建立 SurfaceTexture,並在 TextureViewPreview.SurfaceProvider 上進行設定。
  • TextureView 擷取 SurfaceTexture,並設定在 Preview.SurfaceProvider 上。
  • SurfaceView 取得 Surface,並設定在 Preview.SurfaceProvider 上。

如果發生上述任一情況,Preview 就會停止將影格串流至 PreviewView

在版面配置中加入 PreviewView

下列範例顯示版面配置中的 PreviewView

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

要求 CameraProvider

下列程式碼顯示 CameraProvider 的要求方式:

Kotlin

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

class MainActivity : AppCompatActivity() {
    private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
    override fun onCreate(savedInstanceState: Bundle?) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    }
}

Java

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

public class MainActivity extends AppCompatActivity {
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    }
}

檢查 CameraProvider 適用性

要求 CameraProvider 後,請在建立檢視畫面時確認初始化成功。以下程式碼說明如何執行這項作業:

Kotlin

cameraProviderFuture.addListener(Runnable {
    val cameraProvider = cameraProviderFuture.get()
    bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))

Java

cameraProviderFuture.addListener(() -> {
    try {
        ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
        bindPreview(cameraProvider);
    } catch (ExecutionException | InterruptedException e) {
        // No errors need to be handled for this Future.
        // This should never be reached.
    }
}, ContextCompat.getMainExecutor(this));

如需此範例中使用的 bindPreview 函式範例,請參閱下一節提供的程式碼。

選取相機並繫結生命週期和用途

建立並確認 CameraProvider 後,請執行以下操作:

  1. 建立 Preview
  2. 指定想要的相機 LensFacing 選項。
  3. 將所選相機和任何用途繫結至生命週期。
  4. Preview 連結至 PreviewView

請見以下程式碼範例:

Kotlin

fun bindPreview(cameraProvider : ProcessCameraProvider) {
    var preview : Preview = Preview.Builder()
            .build()

    var cameraSelector : CameraSelector = CameraSelector.Builder()
          .requireLensFacing(CameraSelector.LENS_FACING_BACK)
          .build()

    preview.setSurfaceProvider(previewView.getSurfaceProvider())

    var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}

Java

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
    Preview preview = new Preview.Builder()
            .build();

    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
}

請注意,bindToLifecycle() 會傳回 Camera 物件。如要進一步瞭解如何控管相機輸出內容 (例如縮放和曝光),請參閱相機輸出內容相關說明。

您已完成相機預覽實作內容。建構應用程式,並確認應用程式和功能中顯示的預覽可以正常運作。

PreviewView 的其他控制項

CameraX PreviewView 提供一些用來設定屬性的其他 API,例如:

實作模式

PreviewView 可以使用下列其中一種模式,將預覽串流轉譯至目標 View

  • PERFORMANCE 為預設模式。PreviewView 會使用 SurfaceView 顯示影片串流,但在某些情況下會改回使用 TextureViewSurfaceView 具有專屬繪圖介面,較有可能透過內部硬體合成器實作硬體疊加,特別是預覽影片上方沒有其他 UI 元素 (例如按鈕) 的情況。只要使用硬體疊加進行轉譯,影片影格就會避免使用 GPU 路徑,進而減少平台耗電量和延遲時間。

  • COMPATIBLE 模式。在此模式下,PreviewView 會使用沒有專屬繪圖介面 (與 SurfaceView 不同) 的 TextureView。因此,必須以混合的方式轉譯才能顯示影片。在這個額外步驟中,應用程式可以執行其他處理程序,例如不受限制地縮放及旋轉影片。

使用 PreviewView.setImplementationMode() 選取應用程式適用的實作模式。如果預設的 PERFORMANCE 模式不適用於應用程式,可以參考以下程式碼範例,瞭解如何設定 COMPATIBLE 模式:

Kotlin

// viewFinder is a PreviewView instance
viewFinder.implementationMode = PreviewView.ImplementationMode.COMPATIBLE

縮放類型

如果預覽影片的解析度與目標 PreviewView 的尺寸不同,就需要配合檢視畫面裁剪影片內容或添加上下黑邊 (維持原始顯示比例)。為此,PreviewView 提供下列 ScaleTypes

  • FIT_CENTERFIT_STARTFIT_END 可用於添加上下黑邊。完整的影片內容會盡可能縮放 (放大或縮小) 至目標 PreviewView 可顯示的最大尺寸。不過,雖然這種做法可以顯示完整的影片影格,畫面中的某部分可能會呈現空白。根據您在三種縮放類型之中選擇的類型,影片影格會與目標 View 的中心點、起點或結尾對齊。

  • FILL_CENTERFILL_STARTFILL_END 可用於裁剪。如果影片不符合 PreviewView 的顯示比例,則只會顯示部分內容,但影片會填滿整個 PreviewView

CameraX 採用的預設縮放類型為 FILL_CENTER。使用 PreviewView.setScaleType() 即可設定應用程式最適用的縮放類型。下列程式碼範例可設定 FIT_CENTER 縮放類型:

Kotlin

// viewFinder is a PreviewView instance
viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER

顯示影片的程序包括下列步驟:

  1. 縮放影片:
    • 如果是 FIT_* 縮放類型,請使用 min(dst.width/src.width, dst.height/src.height) 縮放影片。
    • 如果是 FILL_* 縮放類型,請使用 max(dst.width/src.width, dst.height/src.height) 縮放影片。
  2. 將縮放後的影片與目的地 PreviewView 對齊:
    • 如果是 FIT_CENTER/FILL_CENTER,縮放後的影片與目的地 PreviewView 會依據中心點對齊。
    • 如果是 FIT_START/FILL_START,縮放後的影片與目的地 PreviewView 會依據各自的左上角對齊。
    • 如果是 FIT_END/FILL_END,縮放後的影片與目的地 PreviewView 會依據各自的右下角對齊。

舉例來說,以下是 640x480 的來源影片和 1920x1080 的目的地 PreviewView

顯示 640x480 影片與 1920x1080 預覽畫面相比的圖片

下圖顯示 FIT_START/FIT_CENTER/FIT_END 的縮放程序:

顯示 FIT_START、FIT_CENTER 和 FIT_END 縮放程序的圖片

整體程序的運作方式如下:

  1. 使用 min(1920/640, 1080/480) = 2.25 縮放影片影格 (保留原始顯示比例),取得 1440x1080 的中繼影片影格。
  2. 將 1440x1080 影片影格與 1920x1080 PreviewView 對齊。
    • 如果是 FIT_CENTER,將影片影格與 PreviewView 視窗的中心對齊。PreviewView 起始和結束的 240 像素欄為空白。
    • 如果是 FIT_START,將影片影格與 PreviewView 視窗的起點 (左上角) 對齊。PreviewView 結束的 480 像素欄為空白。
    • 如果是 FIT_END,將影片影格與 PreviewView 視窗的結尾 (右下角) 對齊。PreviewView 起始的 480 像素欄為空白。

下圖顯示 FILL_START/FILL_CENTER/FILL_END 的縮放程序:

顯示 FILL_START、FILL_CENTER 和 FILL_END 縮放程序的圖片

程序的運作方式如下:

  1. 使用 max(1920/640, 1080/480) = 3 縮放影片影格,取得 1920x1440 的影片影格 (大於 PreviewView 的尺寸)。
  2. 配合 1920x1080 PreviewView 視窗裁剪 1920x1440 影片影格。
    • 如果是 FILL_CENTER,以 1920x1440 縮放後影片的中心為準,裁剪出 1920x1080 的大小。這時無法顯示影片上方和底部的 180 行內容。
    • 如果是 FILL_START,以 1920x1440 縮放後影片的起點為準,裁剪出 1920x1080 的大小。這時無法顯示影片底部的 360 行內容。
    • 如果是 FILL_END,以 1920x1440 縮放後影片的結尾為準,裁剪出 1920x1080 的大小。這時無法顯示影片上方的 360 行內容。

其他資源

如要進一步瞭解 CameraX,請參閱下列其他資源。

程式碼研究室

  • 開始使用 CameraX
  • 程式碼範例

  • CameraX 範例應用程式