OK, vì vậy tôi nghĩ rằng không có câu trả lời đầy đủ cho vấn đề kéo dài xem trước máy ảnh nói chung. Hoặc ít nhất tôi đã không tìm thấy một. Ứng dụng của tôi cũng bị hội chứng kéo dài này và tôi phải mất một thời gian để cùng nhau giải đáp một giải pháp từ tất cả các câu trả lời của người dùng trên cổng thông tin và internet này.
Tôi đã thử giải pháp của @ Hesam nhưng nó không hoạt động và khiến cho bản xem trước máy ảnh của tôi bị biến dạng lớn.
Đầu tiên tôi hiển thị mã của giải pháp của tôi (các phần quan trọng của mã) và sau đó tôi giải thích lý do tại sao tôi thực hiện các bước đó. Có chỗ để sửa đổi hiệu suất.
Bố cục xml hoạt động chính:
<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>
Xem trước máy ảnh:
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;
}
}
Hoạt động chủ yêu:
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;
}
}
Bình luận của tôi:
Vấn đề của tất cả là, mặc dù bạn tính kích thước camera tối ưu trong getOptimalPreviewSize()
bạn chỉ chọn tỷ lệ gần nhất để vừa với màn hình của bạn. Vì vậy, trừ khi tỷ lệ là chính xác như nhau , bản xem trước sẽ kéo dài.
Tại sao nó sẽ kéo dài? Bởi vì bản xem trước máy ảnh FrameLayout của bạn được đặt trong layout.xml thành match_parent về chiều rộng và chiều cao. Vì vậy, đó là lý do tại sao xem trước sẽ kéo dài đến toàn màn hình.
Điều cần làm là thiết lập chiều rộng và chiều cao bố cục của máy ảnh để phù hợp với tỷ lệ kích thước máy ảnh đã chọn , để chế độ xem trước giữ tỷ lệ khung hình của nó và sẽ không bị biến dạng.
Tôi đã cố gắng sử dụng CameraPreview
lớp để thực hiện tất cả các tính toán và thay đổi bố cục, nhưng tôi không thể tìm ra nó. Tôi đã thử áp dụng giải pháp này , nhưng SurfaceView
không nhận ra getChildCount ()
hoặc getChildAt (int index)
. Tôi nghĩ rằng, cuối cùng tôi đã làm cho nó hoạt động với một tham chiếu đến maLayoutPreview
, nhưng nó đã hoạt động sai và áp dụng tỷ lệ thiết lập cho toàn bộ ứng dụng của tôi và nó đã làm như vậy sau khi bức ảnh đầu tiên được chụp. Vì vậy, tôi để nó đi và di chuyển các sửa đổi bố trí đến MainActivity
.
Trong CameraPreview
Tôi đã thay đổi prSupportedPreviewSizes
và getOptimalPreviewSize()
để công chúng vì vậy tôi có thể sử dụng nó trong MainActivity
. Sau đó, tôi cần kích thước hiển thị (trừ thanh điều hướng / trạng thái nếu có) và chọn kích thước camera tối ưu . Tôi đã cố gắng để có được kích thước RelativeLayout (hoặc FrameLayout) thay vì kích thước hiển thị, nhưng nó đã trả về giá trị bằng không. Giải pháp này không hiệu quả với tôi. Bố cục có giá trị sau onWindowFocusChanged
(kiểm tra trong nhật ký).
Vì vậy, tôi có các phương pháp của mình để tính toán kích thước bố cục để phù hợp với tỷ lệ khung hình của kích thước máy ảnh được chọn. Bây giờ bạn chỉ cần thiết lập LayoutParams
bố trí xem trước máy ảnh của bạn. Thay đổi chiều rộng, chiều cao và căn giữa nó trong cha mẹ.
Có hai sự lựa chọn làm thế nào để tính toán kích thước xem trước. Bạn muốn màn hình vừa với màn hình với các thanh màu đen (nếu windowBackground được đặt thành null) ở hai bên hoặc trên / dưới. Hoặc bạn muốn xem trước phóng to toàn màn hình . Tôi để lại bình luận với nhiều thông tin hơn calcCamPrevDimensions()
.