OK, quindi penso che non ci sia una risposta sufficiente per il problema di stretching dell'anteprima generale della fotocamera. O almeno non ne ho trovato uno. Anche la mia app ha sofferto di questa sindrome da stretching e mi ci è voluto un po 'di tempo per trovare una soluzione da tutte le risposte degli utenti su questo portale e su Internet.
Ho provato la soluzione di @ Hesam ma non ha funzionato e l'anteprima della mia fotocamera è stata notevolmente distorta.
Per prima cosa mostro il codice della mia soluzione (le parti importanti del codice) e poi spiego perché ho preso quei passaggi. C'è spazio per le modifiche alle prestazioni.
Attività principale layout xml:
<RelativeLayout
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:id="@+id/camera_preview"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
Anteprima della fotocamera:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder prHolder;
private Camera prCamera;
public List<Camera.Size> prSupportedPreviewSizes;
private Camera.Size prPreviewSize;
@SuppressWarnings("deprecation")
public YoCameraPreview(Context context, Camera camera) {
super(context);
prCamera = camera;
prSupportedPreviewSizes = prCamera.getParameters().getSupportedPreviewSizes();
prHolder = getHolder();
prHolder.addCallback(this);
prHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
prCamera.setPreviewDisplay(holder);
prCamera.startPreview();
} catch (IOException e) {
Log.d("Yologram", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (prHolder.getSurface() == null){
return;
}
try {
prCamera.stopPreview();
} catch (Exception e){
}
try {
Camera.Parameters parameters = prCamera.getParameters();
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
parameters.setPreviewSize(prPreviewSize.width, prPreviewSize.height);
prCamera.setParameters(parameters);
prCamera.setPreviewDisplay(prHolder);
prCamera.startPreview();
} catch (Exception e){
Log.d("Yologram", "Error starting camera preview: " + e.getMessage());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (prSupportedPreviewSizes != null) {
prPreviewSize =
getOptimalPreviewSize(prSupportedPreviewSizes, width, height);
}
}
public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
Attività principale:
public class MainActivity extends Activity {
...
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
maCamera = getCameraInstance();
maLayoutPreview = (FrameLayout) findViewById(R.id.camera_preview);
maPreview = new CameraPreview(this, maCamera);
Point displayDim = getDisplayWH();
Point layoutPreviewDim = calcCamPrevDimensions(displayDim,
maPreview.getOptimalPreviewSize(maPreview.prSupportedPreviewSizes,
displayDim.x, displayDim.y));
if (layoutPreviewDim != null) {
RelativeLayout.LayoutParams layoutPreviewParams =
(RelativeLayout.LayoutParams) maLayoutPreview.getLayoutParams();
layoutPreviewParams.width = layoutPreviewDim.x;
layoutPreviewParams.height = layoutPreviewDim.y;
layoutPreviewParams.addRule(RelativeLayout.CENTER_IN_PARENT);
maLayoutPreview.setLayoutParams(layoutPreviewParams);
}
maLayoutPreview.addView(maPreview);
}
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
private Point getDisplayWH() {
Display display = this.getWindowManager().getDefaultDisplay();
Point displayWH = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(displayWH);
return displayWH;
}
displayWH.set(display.getWidth(), display.getHeight());
return displayWH;
}
private Point calcCamPrevDimensions(Point disDim, Camera.Size camDim) {
Point displayDim = disDim;
Camera.Size cameraDim = camDim;
double widthRatio = (double) displayDim.x / cameraDim.width;
double heightRatio = (double) displayDim.y / cameraDim.height;
// use ">" to zoom preview full screen
if (widthRatio < heightRatio) {
Point calcDimensions = new Point();
calcDimensions.x = displayDim.x;
calcDimensions.y = (displayDim.x * cameraDim.height) / cameraDim.width;
return calcDimensions;
}
// use "<" to zoom preview full screen
if (widthRatio > heightRatio) {
Point calcDimensions = new Point();
calcDimensions.x = (displayDim.y * cameraDim.width) / cameraDim.height;
calcDimensions.y = displayDim.y;
return calcDimensions;
}
return null;
}
}
Il mio commento:
Il punto di tutto questo è che, anche se si calcola la dimensione ottimale della telecamera in getOptimalPreviewSize()
solamente scegliere il rapporto più vicino per adattarla allo schermo. Quindi, a meno che il rapporto sia esattamente lo stesso, l'anteprima si allungherà.
Perché si allungherà? Perché l'anteprima della videocamera FrameLayout è impostata in layout.xml su match_parent in larghezza e altezza. Ecco perché l'anteprima si estende a schermo intero.
Ciò che deve essere fatto è impostare la larghezza e l'altezza del layout dell'anteprima della fotocamera in modo che corrispondano al rapporto dimensioni della telecamera scelto , in modo che l'anteprima mantenga le proporzioni e non distorca.
Ho provato a usare la CameraPreview
classe per fare tutti i calcoli e le modifiche al layout, ma non sono riuscito a capirlo. Ho provato ad applicare questa soluzione , ma SurfaceView
non lo riconoscogetChildCount ()
o getChildAt (int index)
. Penso che alla fine abbia funzionato con un riferimento a maLayoutPreview
, ma si è comportato male e ha applicato il rapporto impostato a tutta la mia app e lo ha fatto dopo aver scattato la prima foto. Quindi l'ho lasciato andare e ho spostato le modifiche al layout in MainActivity
.
In CameraPreview
ho cambiato prSupportedPreviewSizes
e getOptimalPreviewSize()
al pubblico in modo da poterlo utilizzare in MainActivity
. Quindi avevo bisogno delle dimensioni del display (meno la barra di navigazione / stato, se presente) e ho scelto le dimensioni ottimali della videocamera . Ho cercato di ottenere la dimensione RelativeLayout (o FrameLayout) anziché la dimensione di visualizzazione, ma stava restituendo un valore zero. Questa soluzione non ha funzionato per me. Il layout ha ottenuto il suo valore dopo onWindowFocusChanged
(verificato nel registro).
Quindi ho i miei metodi per calcolare le dimensioni del layout in modo che corrispondano alle proporzioni della dimensione della telecamera scelta. Ora devi solo impostare LayoutParams
il layout di anteprima della fotocamera. Modifica la larghezza, l'altezza e centrala nel genitore.
Esistono due opzioni su come calcolare le dimensioni dell'anteprima. O vuoi che si adatti allo schermo con barre nere (se windowBackground è impostato su null) sui lati o in alto / in basso. Oppure vuoi che l'anteprima venga ingrandita a schermo intero . Ho lasciato un commento con maggiori informazioni in calcCamPrevDimensions()
.