Tamam, bence yeterli cevap yok genel kamera önizleme germe sorunu için . Ya da en azından bir tane bulamadım. Uygulamam da bu germe sendromu yaşadı ve bu portal ve internetteki tüm kullanıcı cevaplarından bir çözüm birlikte bulmaca yapmak biraz zaman aldı.
Hesam'ın çözümünü denedim ama işe yaramadı ve kamera önizlememi büyük ölçüde .
Önce çözümümün kodunu (kodun önemli kısımlarını) gösterdim ve neden bu adımları attığımı açıklıyorum. Performans değişiklikleri için yer var.
Ana faaliyet xml düzeni:
<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>
Kamera Önizleme:
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;
}
}
Ana aktivite:
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;
}
}
Yorumum:
Tüm bu noktada size hesaplamak rağmen yani, optimum kamera boyutunu içinde getOptimalPreviewSize()
size sadece seçmek en yakın oran ekranınıza sığacak şekilde. Dolayısıyla, oran tam olarak aynı değilse önizleme uzayacaktır.
Neden esneyecek? FrameLayout kamera önizlemeniz layout.xml dosyasında genişlik ve yükseklikte match_parent olarak ayarlandığından . Bu yüzden önizleme tam ekrana kadar uzanır.
Yapılması gereken, kamera önizleme düzeni genişliğini ve yüksekliğini seçilen kamera boyutu oranına uyacak şekilde ayarlamaktır , böylece önizleme en boy oranını korur ve deforme olmaz.
CameraPreview
Tüm hesaplamaları ve düzen değişikliklerini yapmak için sınıfı kullanmaya çalıştım , ama anlayamadım. Bu çözümü uygulamaya çalıştım ama SurfaceView
tanımıyor getChildCount ()
ya da getChildAt (int index)
. Sanırım, sonunda referans olarak çalıştım maLayoutPreview
, ancak yanlış davranıyordu ve set oranını tüm uygulamama uyguladı ve ilk resim çekildikten sonra bunu yaptı. Bu yüzden bıraktım ve düzen değişikliklerini MainActivity
.
Gelen CameraPreview
Değiştim prSupportedPreviewSizes
ve getOptimalPreviewSize()
hiç kamuoyuna ben bunu kullanabilmesi MainActivity
. Ardından ekran boyutlarına (varsa eksi gezinme / durum çubuğuna) ihtiyacım vardı ve en uygun kamera boyutunu seçtim . Görüntü boyutu yerine RelativeLayout (veya FrameLayout) boyutunu almaya çalıştım, ancak sıfır değeri döndürüyordu. Bu çözüm benim için işe yaramadı. Düzen, değerinden sonra varonWindowFocusChanged
(günlükte kontrol edilir).
Bu yüzden, seçilen kamera boyutunun en boy oranına uyması için düzen boyutlarını hesaplama yöntemlerim var. Şimdi sadeceLayoutParams
kamera önizleme düzeninizi . Genişliği, yüksekliği değiştirin ve üst öğede ortalayın.
Önizleme boyutlarının nasıl hesaplanacağı iki seçenek vardır. Ya ekranın kenarlarında veya üstte / altta siyah çubuklarla (windowBackground boş olarak ayarlanmışsa) sığmasını istiyorsunuz. Veya önizlemenin tam ekrana yakınlaştırılmasını istiyorsunuz . İçinde daha fazla bilgi içeren yorum bıraktım calcCamPrevDimensions()
.