좋아, 그래서 일반적인 카메라 미리보기 스트레칭 문제에 대한 충분한 대답이 없다고 생각 합니다. 아니면 적어도 하나를 찾지 못했습니다. 내 응용 프로그램은이 스트레칭 증후군을 겪었고이 포털과 인터넷의 모든 사용자 답변에서 솔루션을 함께 모으는 데 시간이 걸렸습니다.
@Hesam의 솔루션을 시도했지만 작동하지 않아 카메라 미리보기가 크게 왜곡되었습니다.
먼저 솔루션의 코드 (코드의 중요한 부분)를 보여준 다음 왜 그 단계를 수행했는지 설명합니다. 성능 수정의 여지가 있습니다.
주요 활동 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>
카메라 미리보기 :
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;
}
}
주요 활동:
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;
}
}
내 논평 :
모든이의 요점은 당신이 계산되지만 있다는 것입니다 최적의 카메라 크기 에 getOptimalPreviewSize()
당신만을 선택 에 가장 가까운 비율 화면에 맞게합니다. 따라서 비율이 정확히 동일 하지 않으면 미리보기가 늘어납니다.
왜 늘어날까요? FrameLayout 카메라 미리보기는 layout.xml 에서 너비와 높이 가 match_parent 로 설정되어 있기 때문 입니다. 그래서 미리보기가 전체 화면으로 확대됩니다.
수행 할 작업은 선택한 카메라 크기 비율 에 맞게 카메라 미리보기 레이아웃 너비와 높이 를 설정 하여 미리보기가 가로 세로 비율을 유지하고 왜곡되지 않도록하는 것입니다.
CameraPreview
클래스 를 사용하여 모든 계산 및 레이아웃 변경을 시도했지만 이해할 수 없었습니다. 나는 적용하려고 이 솔루션을 하지만, SurfaceView
인식하지 못 getChildCount ()
하거나 getChildAt (int index)
. 나는 결국에 대한 참조로 작동한다고 생각 maLayoutPreview
했지만 잘못 작동하여 전체 응용 프로그램에 설정된 비율을 적용했으며 첫 번째 사진을 찍은 후 그렇게했습니다. 그래서 레이아웃을 수정하고 레이아웃 수정을MainActivity
.
에서 CameraPreview
내가 변경 prSupportedPreviewSizes
과 getOptimalPreviewSize()
에 공공 난에서 사용할 수 있습니다 MainActivity
. 그런 다음 디스플레이 크기 (탐색 / 상태 표시 줄이없는 경우)를 빼고 최적의 카메라 크기를 선택했습니다 . 디스플레이 크기 대신 RelativeLayout (또는 FrameLayout) 크기를 얻으려고했지만 0 값을 반환했습니다. 이 솔루션 은 저에게 효과적이지 않았습니다. 레이아웃은 가치가 있습니다.onWindowFocusChanged
(로그에서 확인).
선택한 카메라 크기의 종횡비와 일치하도록 레이아웃 크기를 계산하는 방법이 있습니다. 이제 설정 만하면됩니다.LayoutParams
카메라 미리보기 레이아웃 됩니다. 너비, 높이를 변경하고 부모 중심에 배치하십시오.
미리보기 크기를 계산하는 방법에는 두 가지가 있습니다. 측면 또는 상단 / 하단에 검은 색 막대 (windowBackground가 null로 설정된 경우)가 있는 화면에 맞출 수 있습니다 . 또는 미리보기 를 전체 화면으로 확대 하고자합니다 . 에 더 많은 정보가 담긴 의견을 남겼습니다 calcCamPrevDimensions()
.