Search code examples
angulartypescriptandroid-studioionic-frameworkcapacitor

Capacitor camera preview's preview is overlaid with the action buttons


I'm ussing this Capacitor CameraPreview Library to use the camera functions of the device, but for some strange reason when exporting to an android device the camera's buttons overlap with the preview. It's weird because only happens in android, while working on it on chrome (and even chrome mobile aspect ration simulation) works fine as intended.

This is the code that runs it

Component

cameraStart() {
    const cameraPreviewOptions: CameraPreviewOptions = {
      position: 'rear',
      parent: 'cameraPreview',
      className: 'cameraPreview'
    }
    CameraPreview.start(cameraPreviewOptions)
    this.cameraActive = true
  }

  async stopCamera() {
    await CameraPreview.stop()
    this.cameraActive= false
  }

  async captureImage() {
    const cameraPreviewPictureOptions: CameraPreviewPictureOptions = {
      quality:90
    }
    const result = await CameraPreview.capture(cameraPreviewPictureOptions)
    let image = `data:image/jpeg;base64,${result.value}`
    this.user.person.photo = image
    this.imgUploader.selectProfilePic(this.imgUploader.dataURLtoFile(image, `pp-img_${new Date().getTime()}`), this.user.firebase_id) 
    this.stopCamera()
  }

  async turnFlashOn() {
    const flashModes = await CameraPreview.getSupportedFlashModes();
    //const supportedFlashModes: CameraPreviewFlashMode[] = flashModes.result;
    //console.log(supportedFlashModes)
    this.flashActive = !this.flashActive
    const cameraPreviewFlashMode: CameraPreviewFlashMode = this.flashActive ? 'torch' : 'off'

    CameraPreview.setFlashMode(cameraPreviewFlashMode);
  }

  flipCamera() { CameraPreview.flip() }

Document

<ion-header *ngIf="!cameraActive">
  <ion-toolbar>
    <ion-buttons slot="start" (click)="dismiss()">
      <ion-button>
        <ion-icon slot="icon-only" name="close-outline"></ion-icon>
      </ion-button>
    </ion-buttons>
    <ion-title>{{ 'image-editing' | translate }}</ion-title>
  </ion-toolbar>
</ion-header>
<ion-content>
  <div id="cameraPreview" class="cameraPreview">
    <div *ngIf="cameraActive">
      <ion-button color="light" (click)="stopCamera()" expand="block" id="close">
        <ion-icon name="arrow-undo" slot="icon-only"></ion-icon>
      </ion-button>
      <ion-button color="light" (click)="captureImage()" expand="block" id="capture">
        <ion-icon name="camera" slot="icon-only"></ion-icon>
      </ion-button>
      <ion-button color="light" (click)="flipCamera()" expand="block" id="flip">
        <ion-icon name="camera-reverse" slot="icon-only"></ion-icon>
      </ion-button>
      <ion-button color="light" (click)="turnFlashOn()" expand="block" id="flash">
        <ion-icon *ngIf="flashActive" color="warning" name="flash" slot="icon-only"></ion-icon>
        <ion-icon *ngIf="!flashActive" name="flash-off" slot="icon-only"></ion-icon>
      </ion-button>
    </div>
  </div>
</ion-content>

Sass

img {
    width: 100%;
    height: auto;
}

ion-content {
    --background: transparent!important;
}

.overlay {
    position: absolute;
    width: 100%;
    height: 100%;
    z-index: 10%
}

.cameraPreview {
    display: flex;
    width: 100%;
    height: 100%;
    position: absolute;
}

.image-overlay {
    z-index: 1;
    position: absolute;
    left: 25%;
    top: 25%;
    width: 50%;
}

#capture {
    position: absolute;
    bottom: 25px;
    left: calc(50% - 37.5px);
    width: 72px;
    height: 72px;
    z-index: 11;
}

#close {
    position: absolute;
    bottom: 30px;
    left: calc(50% - 150px);
    width: 50px;
    height: 50px;
    z-index: 11;
}

#flip {
    position: absolute;
    bottom: 30px;
    left: calc(50% + 97px);
    width: 50px;
    height: 50px;
    z-index: 11;
}

#flash {
    position: absolute;
    top: 30px;
    left: calc(50% + 97px);
    width: 50px;
    height: 50px;
    z-index: 11;
}

#close::part(native) {
    border-radius: 30px;
}

#capture::part(native) {
    border-radius: 45px;
}

#flip::part(native) {
    border-radius: 30px;
}

#flash::part(native) {
    border-radius: 30px;
}

Here's a picture of it running on android studio:

 Android Studio

Here's a picture Running on an actual android device

 True Android Device

Here's running on chrome (btw don't mind the borders, this pc has a crappy camara)

enter image description here

As a side note, the flash doesn't seem to be working either, but i don't know if it has to be the library or if i'm doing something wrong.


Solution

  • I made a syntactic and a logical error. First in the CSS the camera's overlay needs to be set at a constant value.

    .overlay {
        position: absolute;
        width: 100%;
        height: 100%;
        z-index: 10;
    }
    
    .cameraPreview {
        display: flex;
        width: 100%;
        height: 100%;
        position: absolute;
    }
    

    So the z-index is less in the order that the buttons go.

    Second of all the flash boolean witch works, but as i'm sending the order through a constant the value wouldn't change from false anyhow, but just change it to a variable and it should work.

    async turnFlashOn() {
        const flashModes = await CameraPreview.getSupportedFlashModes();
        //const supportedFlashModes: CameraPreviewFlashMode[] = flashModes.result;
        //console.log(supportedFlashModes)
        this.flashActive = !this.flashActive
        let cameraPreviewFlashMode: CameraPreviewFlashMode = this.flashActive ? 'on' : 'off'
    
        CameraPreview.setFlashMode(cameraPreviewFlashMode);
      }