J'essaie de développer ma propre activité de caméra, mais j'ai un problème que je n'arrive pas à résoudre ...
Ce que je veux, c'est quelque chose de très similaire au cadre photo instagram, et voici ce que j'obtiens:
Quand devrais-je obtenir quelque chose comme ça:
et...
quand je devrais obtenir quelque chose comme:
Je pense que je gère bien l'aperçu de SurfaceView et de la caméra, en utilisant uniquement
Camera.Parameters parameters = camera.getParameters();
camera.setDisplayOrientation(90);
et SurfaceView personnalisé:
public class SquaredSurfaceView extends SurfaceView {
private int width;
private int height;
public SquaredSurfaceView(Context context) {
super(context);
}
public SquaredSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquaredSurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = width;
setMeasuredDimension(width, width);
}
public int getViewWidth() {
return width;
}
public int getViewHeight() {
return height;
}
}
Qu'est-ce que je fais mal ?? :-(
Comme indiqué précédemment, vous devez trouver la taille d'aperçu correcte (celle avec le rapport d'aspect 1: 1) et vous devez probablement utiliser FrameLayout pour SurfacePreview. Il semble que vous ayez un problème de rapport d'aspect, peut-être avez-vous la bonne taille d'aperçu, mais vous le placez dans une disposition incorrecte.
Une autre solution pourrait être (tout comme Instagram) de rendre votre appareil photo en taille réelle, puis de masquer certaines zones de la mise en page juste pour le faire ressembler à un carré. Ensuite, par logiciel, il faudrait couper l'image pour en faire un vrai carré.
J'espère que cela vous aide
La solution qui fonctionne pour moi est la 2e réponse, mais parce que nous devons faire pivoter la caméra de 90º, il est nécessaire de commuter la LARGEUR avec la HAUTEUR, quelque chose comme ça ...
camera.setDisplayOrientation(90);
Camera.Parameters params= camera.getParameters();
surfaceView.getLayoutParams().width=params.getPreviewSize().height;
surfaceView.getLayoutParams().height=params.getPreviewSize().width;
J'espère que cette solution vous aidera !! :RÉ
J'ai eu le même problème avec une vue carrée - l'a résolu simplement en réglant la taille de la caméra SurfaceView sur la taille de la vue où je voulais la dessiner. Pas de calculs compliqués et ça marche pour moi. Voir ma réponse ici pour toute la méthode: https://stackoverflow.com/a/39430615/5181489
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
...
params.setPreviewSize(viewParams.height, viewParams.width);
camera.setParameters(params);
ma solution est plus comme la construction d'un masque carré, puis pour le placer sur la surface d'aperçu.
Vous aurez besoin de 3 choses principalement, d'abord un composant de cadre carré. J'ai créé un composant personnalisé:
package com.example.squaredviewer;
import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.Display;
import Android.view.WindowManager;
import Android.widget.RelativeLayout;
/**
* Created by yadirhb on 14-08-2015.
*/
public class SquaredFrame extends RelativeLayout{
public SquaredFrame(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(size, size);
}
}
En fonction de la version Android de l'API pour laquelle vous développez, vous devrez peut-être ajouter une autre surcharge de constructeur. Pour KitKat, c'est très bien.
La deuxième étape consiste à créer la mise en page:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="horizontal"
Android:visibility="visible">
<RelativeLayout
Android:id="@+id/camera_preview"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentLeft="false"
Android:layout_alignParentTop="false"
Android:layout_centerInParent="true"
Android:background="#ffffff">
</RelativeLayout>
<LinearLayout
Android:orientation="horizontal"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<LinearLayout
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_weight="1"
Android:background="#131008">
</LinearLayout>
<com.example.squaredviewer.SquaredFrame
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_centerInParent="true"></com.example.squaredviewer.SquaredFrame>
<LinearLayout
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_weight="1"
Android:background="#131008" />
</LinearLayout>
</RelativeLayout>
Notez que le RelativeLayout "camera_preview" est celui utilisé pour rendre l'aperçu, il est centré et a un LinearLayout qui contient le composant carré. Il s'agit en fait du "masque" et il couvre l'aperçu de la caméra. Notez également qu'à l'exception du SquaredFrame, qui est transparent, les deux autres sont colorés en arrière-plan en noir.
Maintenant, la vue de la surface, pour l'aperçu de la caméra dans lequel la surface est dimensionnée selon le rapport d'aspect.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private final String TAG = "PIC-FRAME";
private SurfaceHolder mHolder;
private Camera mCamera;
private Display display;
public CameraPreview(Activity context, Camera camera) {
super(context);
mCamera = camera;
display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
setKeepScreenOn(true);
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
this.getHolder().removeCallback(this);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
try {
// stop preview before making changes
mCamera.stopPreview();
// set preview size and make any resize, rotate or
// reformatting changes here
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
// You need to choose the most appropriate previewSize for your app
Camera.Size previewSize = parametes.getSupportedPreviewSizes().get(0);
parameters.setPreviewSize(previewSize.width, previewSize.height);
// start preview with new settings
mCamera.setParameters(parameters);
// Set the holder size based on the aspect ratio
int size = Math.min(display.getWidth(), display.getHeight());
double ratio = (double) previewSize.width / previewSize.height;
mHolder.setFixedSize((int)(size * ratio), size);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
}
Maintenant, tout doit être lié dans la classe d'activité
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_picture_taker);
mDecorView = getWindow().getDecorView();
//mCamera = a camera instance;
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
//Layout where camera preview is shown.
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
//FrameLayout stack controllers inside and superpose them.
preview.addView(mPreview, 0);
// TODO
}
Un peu long, mais j'espère que ce sera utile pour plus d'un. :-)