ठीक है, इसलिए मुझे लगता है कि सामान्य कैमरा पूर्वावलोकन स्ट्रेचिंग समस्या के लिए कोई पर्याप्त जवाब नहीं है। या कम से कम मुझे एक नहीं मिला। मेरे ऐप को इस स्ट्रेचिंग सिंड्रोम का भी सामना करना पड़ा और मुझे इस पोर्टल और इंटरनेट पर सभी उपयोगकर्ता के जवाबों के समाधान के लिए एक साथ पहेली करने में थोड़ा समय लगा।
मैंने @ हेसम के समाधान की कोशिश की, लेकिन यह काम नहीं किया और मेरे कैमरे के पूर्वावलोकन को प्रमुख रूप से विकृत कर दिया।
पहले मैं अपने समाधान का कोड (कोड के महत्वपूर्ण भाग) दिखाता हूं और फिर मैं समझाता हूं कि मैंने वे कदम क्यों उठाए। प्रदर्शन संशोधनों के लिए जगह है।
मुख्य गतिविधि 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()
आप केवल लेने निकटतम अनुपात अपनी स्क्रीन फिट करने के लिए। इसलिए जब तक कि अनुपात ठीक वैसा ही न हो , पूर्वावलोकन पूर्वावलोकन करेगा।
क्यों खिंचेगा? क्योंकि आपका फ्रेम -आउट कैमरा पूर्वावलोकन लेआउट । Xml में चौड़ाई और ऊंचाई में match_parent में सेट किया गया है । यही कारण है कि पूर्वावलोकन पूर्ण स्क्रीन तक फैल जाएगा।
चुने गए कैमरा आकार अनुपात से मिलान करने के लिए कैमरा पूर्वावलोकन लेआउट की चौड़ाई और ऊंचाई निर्धारित करने के लिए क्या करना चाहिए , इसलिए पूर्वावलोकन इसका पहलू अनुपात रखता है और विकृत नहीं करेगा।
मैंने CameraPreview
सभी गणनाओं और लेआउट परिवर्तनों को करने के लिए कक्षा का उपयोग करने की कोशिश की , लेकिन मैं इसका पता नहीं लगा सका। मैंने इस समाधान को लागू करने की कोशिश की , लेकिन SurfaceView
पहचान नहीं करता है getChildCount ()
या getChildAt (int index)
। मुझे लगता है, मैंने इसे अंततः एक संदर्भ के साथ काम कर लिया maLayoutPreview
, लेकिन यह दुर्व्यवहार कर रहा था और मेरे पूरे ऐप पर सेट अनुपात लागू किया और पहली तस्वीर लेने के बाद ऐसा किया। इसलिए मैंने इसे जाने दिया और लेआउट संशोधनों को स्थानांतरित कर दिया MainActivity
।
में CameraPreview
मैं बदल गया prSupportedPreviewSizes
और getOptimalPreviewSize()
करने के लिए सार्वजनिक तो मैं में उपयोग कर सकते हैं MainActivity
। तब मुझे डिस्प्ले आयामों की आवश्यकता थी (यदि एक है तो नेविगेशन / स्टेटस बार को घटा दें) और चुने हुए इष्टतम कैमरा आकार । मैंने प्रदर्शन आकार के बजाय RelativeLayout (या FrameLayout) आकार प्राप्त करने का प्रयास किया, लेकिन यह शून्य मान लौटा रहा था। यह समाधान मेरे काम नहीं आया। बाद में onWindowFocusChanged
(लॉग में जाँच की गई) लेआउट का मान है ।
इसलिए मेरे पास चुने हुए कैमरा आकार के पहलू अनुपात से मेल खाने के लिए लेआउट आयामों की गणना करने के लिए मेरे तरीके हैं। अब आपको बस LayoutParams
अपना कैमरा प्रीव्यू लेआउट सेट करना होगा। चौड़ाई को बदलें, ऊँचाई और इसे माता-पिता में केन्द्रित करें।
पूर्वावलोकन आयामों की गणना करने के लिए दो विकल्प हैं। या तो आप इसे काली पट्टियों के साथ स्क्रीन पर फिट करना चाहते हैं (यदि विंडोबैकग्राउंड को शून्य पर सेट किया गया है) पक्षों या शीर्ष / तल पर। या आप चाहते हैं कि पूर्वावलोकन पूरी स्क्रीन पर ज़ूम इन हो । मैंने अधिक जानकारी के साथ टिप्पणी छोड़ दी calcCamPrevDimensions()
।