Camera2 API竖屏预览拉伸问题求助(三星Android9已试多方案无效)
Hey there, let's tackle this stubborn Samsung Android 9 Camera2 preview stretching issue in portrait mode. I’ve dealt with similar device-specific quirks before, so here are targeted fixes that should work:
Samsung's Android 9 ROM has a unique quirk in how it calculates TextureView transformation matrices for portrait mode. Skip the default AutoFitTextureView logic and manually adjust the matrix with these steps:
- In the
onSurfaceTextureAvailablecallback, fetch camera sensor orientation and your selected preview size first:CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); Size previewSize = // Your chosen optimal preview size - Calculate the correct scale and apply the matrix with Samsung-specific adjustments:
float ratio; int viewWidth = textureView.getWidth(); int viewHeight = textureView.getHeight(); Configuration config = getResources().getConfiguration(); if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { // Swap width/height ratio for Samsung's portrait handling ratio = (float) previewSize.getHeight() / previewSize.getWidth(); float scaleX, scaleY; if (sensorOrientation == 90 || sensorOrientation == 270) { scaleX = ratio; scaleY = 1.0f; // Adjust scale to fit view without stretching if (scaleX * viewWidth < viewHeight) { scaleX = (float) viewHeight / viewWidth / ratio; } else { scaleY = (float) viewWidth / viewHeight * ratio; } } else { scaleX = 1.0f; scaleY = ratio; if (scaleY * viewHeight < viewWidth) { scaleY = (float) viewWidth / viewHeight / ratio; } else { scaleX = (float) viewHeight / viewWidth * ratio; } } // Apply transformation matrix with rotation and center alignment Matrix matrix = new Matrix(); matrix.setScale(scaleX, scaleY); matrix.postRotate(90); // Match portrait orientation float centerX = viewWidth / 2f; float centerY = viewHeight / 2f; matrix.postTranslate( (viewWidth - previewSize.getHeight() * scaleX) / 2, (viewHeight - previewSize.getWidth() * scaleY) / 2 ); textureView.setTransform(matrix); }
Some Samsung devices force stretching instead of cropping when preview size aspect ratio doesn't match the screen. Filter supported sizes to find an exact match:
- Use this method to pick the optimal size:
private Size chooseOptimalSize(Size[] choices, int viewWidth, int viewHeight) { List<Size> exactMatches = new ArrayList<>(); float targetRatio; Configuration config = getResources().getConfiguration(); // Adjust target ratio for portrait mode if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { targetRatio = (float) viewHeight / viewWidth; } else { targetRatio = (float) viewWidth / viewHeight; } // Find sizes with exact aspect ratio match for (Size size : choices) { float sizeRatio = (float) size.getWidth() / size.getHeight(); if (Math.abs(sizeRatio - targetRatio) < 0.001f) { exactMatches.add(size); } } // Pick the largest exact match for best resolution if (!exactMatches.isEmpty()) { return Collections.max(exactMatches, (a, b) -> Long.compare( (long) a.getWidth() * a.getHeight(), (long) b.getWidth() * b.getHeight() )); } // Fallback to closest match if no exact fit Size bestFit = choices[0]; float smallestDiff = Float.MAX_VALUE; for (Size size : choices) { float sizeRatio = (float) size.getWidth() / size.getHeight(); float diff = Math.abs(sizeRatio - targetRatio); if (diff < smallestDiff) { smallestDiff = diff; bestFit = size; } } return bestFit; } - Important: Pass the actual measured width/height of your TextureView (not the full screen resolution) to account for status/navigation bars.
If the above fixes fail, some Samsung Android 9 builds have bugs with TextureView hardware acceleration. Try disabling it:
- In your layout XML:
<AutoFitTextureView android:id="@+id/textureView" android:layout_width="match_parent" android:layout_height="match_parent" android:hardwareAccelerated="false" /> - Or programmatically:
textureView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Note: This may reduce preview performance, so only use it as a last resort.
内容的提问来源于stack exchange,提问作者Erum

