ตกลงดังนั้นฉันคิดว่าไม่มีคำตอบเพียงพอสำหรับปัญหาการยืดตัวอย่างกล้องทั่วไป หรืออย่างน้อยก็หาไม่เจอ แอพของฉันมีอาการยืดออกเช่นนี้และต้องใช้เวลาพอสมควรในการไขปริศนาร่วมกันจากคำตอบของผู้ใช้ทั้งหมดบนพอร์ทัลและอินเทอร์เน็ต
ฉันลองวิธีแก้ปัญหาของ @ 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) แทนขนาดจอแสดงผล แต่กลับเป็นค่าศูนย์ วิธีนี้ไม่ได้ผลสำหรับฉัน โครงร่างมีค่าเป็นหลังonWindowFocusChanged
(ถูกตรวจสอบในบันทึก)
ดังนั้นฉันจึงมีวิธีคำนวณขนาดเลย์เอาต์เพื่อให้ตรงกับอัตราส่วนของขนาดกล้องที่เลือก ตอนนี้คุณเพียงแค่ต้องตั้งค่าLayoutParams
เค้าโครงตัวอย่างกล้องของคุณ เปลี่ยนความกว้างความสูงและจัดให้อยู่กึ่งกลางในพาเรนต์
มีสองทางเลือกในการคำนวณขนาดตัวอย่าง คุณต้องการให้พอดีกับหน้าจอที่มีแถบสีดำ (หาก windowBackground ถูกตั้งค่าเป็น null) ที่ด้านข้างหรือด้านบน / ล่าง หรือคุณต้องการแสดงตัวอย่างซูมแบบเต็มหน้าจอ calcCamPrevDimensions()
ผมออกจากความคิดเห็นที่มีข้อมูลเพิ่มเติมใน