Ich habe daran gearbeitet, meine benutzerdefinierte Kameraaktivität unter Android zu erstellen, aber beim Drehen der Kamera wird das Seitenverhältnis der Oberflächenansicht durcheinander gebracht.
In meinem Oncreate für die Aktivität habe ich das Framelayout festgelegt, das die Oberflächenansicht enthält, in der die Parameter der Kamera angezeigt werden.
//FrameLayout that will hold the camera preview
FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);
//Setting camera's preview size to the best preview size
Size optimalSize = null;
camera = getCameraInstance();
double aspectRatio = 0;
if(camera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
aspectRatio = (float)optimalSize.width/optimalSize.height;
}
if(optimalSize!= null){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
previewHolder.setLayoutParams(params);
LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
cameraPreview.setLayoutParams(surfaceParams);
}
cameraPreview.setCamera(camera);
//Adding the preview to the holder
previewHolder.addView(cameraPreview);
Dann habe ich in der Oberflächenansicht die Parameter der Kamera eingestellt, die angezeigt werden sollen
public void setCamera(Camera camera) {
if (mCamera == camera) { return; }
mCamera = camera;
if (mCamera != null) {
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
}
/*
Important: Call startPreview() to start updating the preview surface. Preview must
be started before you can take a picture.
*/
mCamera.startPreview();
}
}
Sie können sehen, dass der LEGO-Mann größer und dünner wird, wenn das Telefon gedreht wird:
Wie kann ich sicherstellen, dass das Seitenverhältnis für meine Kameraansicht korrekt ist?
android
android-camera
surfaceview
preview
aspect-ratio
wissenschaftlich
quelle
quelle
Antworten:
Ich verwende diese Methode -> basierend auf API-Demos, um meine Vorschaugröße zu erhalten:
Wie Sie sehen, müssen Sie Breite und Höhe Ihres Bildschirms eingeben. Diese Methode berechnet das Bildschirmverhältnis basierend auf diesen Werten und wählt dann aus der Liste der unterstützten PreviewSizes das für Sie beste aus den verfügbaren aus. Stellen Sie Ihre unterstützte PreviewSize-Liste an einen Ort, an dem das Kameraobjekt nicht null ist
Und dann können Sie in onMeasure Ihre optimale Vorschau erhalten.
Und dann (in meinem Code in der SurfaceChanged-Methode, wie ich bereits sagte, verwende ich die API-Demostruktur des CameraActivity-Codes, können Sie ihn in Eclipse generieren):
Und ein Hinweis für Sie, denn ich habe fast die gleiche App wie Sie gemacht. Es empfiehlt sich, die Statusleiste auszublenden. Anwendungen wie Instagram machen es. Es reduziert Ihren Bildschirmhöhenwert und ändert Ihren Verhältniswert. Auf einigen Geräten können seltsame Vorschaugrößen angezeigt werden (Ihre SurfaceView wird ein wenig gekürzt).
Und um Ihre Frage zu beantworten, wie können Sie überprüfen, ob Ihr Vorschau-Verhältnis korrekt ist? Dann erhalten Sie Höhe und Breite der Parameter, die Sie eingestellt haben:
Ihr festgelegtes Verhältnis entspricht Höhe / Breite. Wenn die Kamera auf Ihrem Bildschirm gut aussehen soll, muss das Verhältnis von Höhe zu Breite der von Ihnen auf Kamera eingestellten Parameter dem Verhältnis von Höhe (minus Statusleiste) zu Breite Ihres Bildschirms entsprechen.
quelle
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
.Die Lösung von F1Sher ist nett, funktioniert aber manchmal nicht. Insbesondere, wenn Ihre SurfaceView nicht den gesamten Bildschirm abdeckt. In diesem Fall müssen Sie die onMeasure () -Methode überschreiben. Ich habe meinen Code hier als Referenz kopiert.
Da ich die Oberflächenansicht anhand der Breite gemessen habe, habe ich am Ende meines Bildschirms eine kleine weiße Lücke, die ich beabsichtigt ausgefüllt habe. Sie können dieses Problem beheben, wenn Sie die Höhe beibehalten und die Breite erhöhen, indem Sie sie mit dem Verhältnis multiplizieren. Die Oberflächenansicht wird jedoch leicht gequetscht.
quelle
getOptimalPreviewSize
damit dies für mich funktioniert. Liegt das daran, dass die Ausrichtung des Displays auf 90 eingestellt wurde? Ansonsten wurden die Verhältnisberechnungen nicht einmal in der Nähe (Ziel war 1,7 und die Kamera - Verhältnisse kleiner als 1)HINWEIS: MEINE LÖSUNG IST EINE FORTSETZUNG DER HESAM-LÖSUNG: https://stackoverflow.com/a/22758359/1718734
Was ich anspreche: Hesam hat gesagt, dass auf einigen Telefonen ein kleiner weißer Bereich angezeigt wird:
Hesam schlug eine zweite Lösung vor, aber das drückt die Vorschau zusammen. Und auf einigen Geräten verzerrt es stark.
Wie können wir dieses Problem beheben? Es ist einfach ... durch Multiplizieren der Seitenverhältnisse, bis der Bildschirm ausgefüllt ist. Ich habe festgestellt, dass einige beliebte Apps wie Snapchat, WhatsApp usw. auf die gleiche Weise funktionieren.
Sie müssen dies lediglich zur onMeasure-Methode hinzufügen:
Dadurch wird die Bildschirmhöhe berechnet und das Verhältnis zwischen Bildschirmhöhe und mPreviewSize-Höhe ermittelt. Anschließend multipliziert es die Breite und Höhe der Kamera mit dem neuen Höhenverhältnis und stellt die gemessene Abmessung entsprechend ein.
Und das nächste, was Sie wissen, ist Folgendes: D.
Dies funktioniert auch gut mit der Frontkamera. Ich glaube, das ist der beste Weg, dies zu tun. Jetzt muss meine App nur noch die Vorschau selbst speichern, wenn Sie auf "Erfassen" klicken. Aber ja, das ist es.
quelle
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
Methode bekomme ich immer Breite = 0 und Höhe = 0;OK, ich denke, es gibt keine ausreichende Antwort auf das allgemeine Problem mit der Dehnung der Kameravorschau. Zumindest habe ich keinen gefunden. Meine App litt auch unter diesem Stretching-Syndrom und es dauerte eine Weile, bis ich eine Lösung aus allen Benutzerantworten auf diesem Portal und im Internet gefunden hatte.
Ich habe die Lösung von @ Hesam ausprobiert, aber sie hat nicht funktioniert und meine Kamera-Vorschau stark verzerrt.
Zuerst zeige ich den Code meiner Lösung (die wichtigen Teile des Codes) und erkläre dann, warum ich diese Schritte unternommen habe. Es gibt Raum für Leistungsänderungen.
Hauptaktivität XML-Layout:
Kameravorschau:
Hauptaktivität:
Mein Kommentar:
Der Sinn all dessen ist, dass Sie, obwohl Sie die optimale Kameragröße in berechnen
getOptimalPreviewSize()
, nur das nächstgelegene Verhältnis auswählen, das zu Ihrem Bildschirm passt. Wenn das Verhältnis nicht genau gleich ist, wird die Vorschau gedehnt.Warum wird es sich dehnen? Weil Ihre FrameLayout Kameravorschau wird in gesetzt layout.xml zu match_parent in Breite und Höhe. Aus diesem Grund wird die Vorschau auf den Vollbildmodus ausgedehnt.
Sie müssen lediglich die Breite und Höhe des Kamera-Vorschau-Layouts so einstellen , dass sie dem gewählten Kameragrößenverhältnis entsprechen , damit die Vorschau ihr Seitenverhältnis beibehält und nicht verzerrt.
Ich habe versucht, mit der
CameraPreview
Klasse alle Berechnungen und Layoutänderungen vorzunehmen, konnte es aber nicht herausfinden. Ich habe versucht, diese Lösung anzuwenden ,SurfaceView
erkenne aber nichtgetChildCount ()
odergetChildAt (int index)
. Ich denke, ich habe es irgendwann mit einem Verweis aufmaLayoutPreview
zum Laufen gebracht, aber es hat sich schlecht benommen und das eingestellte Verhältnis auf meine gesamte App angewendet, und das tat es, nachdem das erste Bild aufgenommen wurde. Also ließ ich es los und verschob die Layoutänderungen auf dieMainActivity
.In
CameraPreview
ich geändertprSupportedPreviewSizes
undgetOptimalPreviewSize()
zu öffentlich , damit ich es in nutzenMainActivity
. Dann brauchte ich die Anzeigeabmessungen (abzüglich der Navigations- / Statusleiste, falls vorhanden) und wählte die optimale Kameragröße . Ich habe versucht, die RelativeLayout-Größe (oder FrameLayout-Größe) anstelle der Anzeigegröße zu ermitteln, aber es wurde ein Wert von Null zurückgegeben. Diese Lösung hat bei mir nicht funktioniert. Das Layout hat seinen Wert nachonWindowFocusChanged
(im Protokoll überprüft).Ich habe also meine Methoden zur Berechnung der Layoutabmessungen, um sie an das Seitenverhältnis der ausgewählten Kameragröße anzupassen. Jetzt müssen Sie nur noch das
LayoutParams
Layout Ihrer Kameravorschau festlegen . Ändern Sie die Breite, Höhe und zentrieren Sie sie im übergeordneten Element.Es gibt zwei Möglichkeiten, die Vorschaudimensionen zu berechnen. Entweder möchten Sie, dass der Bildschirm mit schwarzen Balken (wenn windowBackground auf null gesetzt ist) an den Seiten oder oben / unten versehen wird. Oder Sie möchten, dass die Vorschau auf Vollbild vergrößert wird . Ich habe einen Kommentar mit weiteren Informationen in hinterlassen
calcCamPrevDimensions()
.quelle
Hallo, das getOptimalPreview (), das hier ist, hat bei mir nicht funktioniert, daher möchte ich meine Version teilen:
quelle
Um diesen Thread zu vervollständigen, füge ich meine Version der Antwort hinzu:
Was ich erreichen wollte: Die Oberflächenansicht sollte nicht gedehnt werden und den gesamten Bildschirm abdecken. Außerdem gab es in meiner App nur einen Querformatmodus.
Lösung:
Die Lösung ist eine extrem kleine Erweiterung der F1sher-Lösung:
=> Der erste Schritt ist die Integration der F1sher-Lösung.
=> Nun kann es in der F1sher-Lösung zu einem Szenario kommen, in dem die Oberflächenansicht nicht den gesamten Bildschirm abdeckt. Die Lösung besteht darin, die Oberflächenansicht größer als die Bildschirmabmessungen zu machen, sodass sie den gesamten Bildschirm abdeckt.
quelle
Ich habe herausgefunden, was das Problem ist - es ist mit Orientierungsänderungen . Wenn Sie die Kameraausrichtung auf 90 oder 270 Grad ändern, müssen Sie Breite und Höhe der unterstützten Größen austauschen, und alles ist in Ordnung.
Auch die Oberflächenansicht sollte in einem Rahmenlayout liegen und den Schwerpunkt haben.
Hier ist ein Beispiel für C # (Xamarin):
Achten Sie darauf, dass die Kameraparameter als Originalgröße (nicht vertauscht) und die Größe der Oberflächenansicht vertauscht werden.
quelle
Ich habe alle oben genannten Lösungen ausprobiert, aber keine davon funktioniert für mich. Schließlich habe ich es selbst gelöst und finde es eigentlich ganz einfach. Es gibt zwei Punkte, bei denen Sie vorsichtig sein müssen.
Diese Vorschaugröße muss eine der von der Kamera unterstützten Auflösungen sein, die wie folgt angezeigt werden können:
Normalerweise entspricht eine der rawSupportedSize der Geräteauflösung.
Zweitens platzieren Sie Ihre SurfaceView in einem FrameLayout und legen die Höhe und Breite des Oberflächenlayouts wie oben in der surfaceChanged-Methode fest
Ok, Dinge erledigt, hoffe das könnte dir helfen.
quelle
Meine Anforderungen sind, dass die Kameravorschau im Vollbildmodus sein und das Seitenverhältnis beibehalten muss. Die Lösung von Hesam und Yoosuf war großartig, aber ich sehe aus irgendeinem Grund ein Problem mit hohem Zoom.
Die Idee ist dieselbe: Lassen Sie das Vorschau-Container-Zentrum im übergeordneten Element und erhöhen Sie die Breite oder Höhe abhängig von den Seitenverhältnissen, bis es den gesamten Bildschirm abdecken kann.
Zu beachten ist, dass sich die Vorschaugröße im Querformat befindet, da wir die Ausrichtung der Anzeige festlegen.
Der Container, dem wir die SurfaceView-Ansicht hinzufügen:
Fügen Sie die Vorschau zu dem Container hinzu, in dessen Aktivität die Mitte im übergeordneten Element steht.
Innerhalb der CameraPreview-Klasse:
quelle
Sie müssen cameraView.getLayoutParams (). Height und cameraView.getLayoutParams (). Width entsprechend dem gewünschten Seitenverhältnis festlegen.
quelle
Ich habe die Berechnungen aufgegeben und einfach die Größe der Ansicht abgerufen, in der die Kameravorschau angezeigt werden soll, und die Vorschaugröße der Kamera in meiner benutzerdefinierten SurfaceView-Implementierung gleich eingestellt (nur gespiegelte Breite / Höhe aufgrund von Drehung):
quelle