Я работал над созданием своей пользовательской активности камеры на Android, но при повороте камеры соотношение сторон вида поверхности испортилось.
В моем режиме для действия я установил структуру кадра, которая содержит вид поверхности, отображающий параметры камеры.
//FrameLayout that will hold the camera preview
FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);
//Setting camera's preview size to the best preview size
Size optimalSize = null;
camera = getCameraInstance();
double aspectRatio = 0;
if(camera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
aspectRatio = (float)optimalSize.width/optimalSize.height;
}
if(optimalSize!= null){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
previewHolder.setLayoutParams(params);
LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
cameraPreview.setLayoutParams(surfaceParams);
}
cameraPreview.setCamera(camera);
//Adding the preview to the holder
previewHolder.addView(cameraPreview);
Затем в окне Surface я установил параметры камеры для отображения
public void setCamera(Camera camera) {
if (mCamera == camera) { return; }
mCamera = camera;
if (mCamera != null) {
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
}
/*
Important: Call startPreview() to start updating the preview surface. Preview must
be started before you can take a picture.
*/
mCamera.startPreview();
}
}
Вы можете видеть, что человек LEGO становится выше и стройнее, когда телефон поворачивается:
Как я могу убедиться в правильности соотношения сторон экрана моей камеры?
android
android-camera
surfaceview
preview
aspect-ratio
scientiffic
источник
источник
Ответы:
Я использую этот метод -> на основе API Демо, чтобы получить размер предварительного просмотра:
Как вы можете видеть, вы должны ввести ширину и высоту экрана. Этот метод рассчитает соотношение экрана на основе этих значений, а затем из списка поддерживаемых размеров просмотра он выберет для вас лучшее из доступных. Получите ваш список SupportPreviewSize в месте, где объект Camera не равен NULL, используя
И затем в onMeasure вы можете получить оптимальный размер предварительного просмотра, например:
И затем (в моем коде в методе SurfaceChanged, как я уже говорил, я использую структуру API Demos кода CameraActivity, вы можете сгенерировать ее в Eclipse):
И один совет для вас, потому что я сделал почти то же приложение, что и вы. Хорошей практикой для Camera Activity является скрытие StatusBar. Такие приложения, как Instagram, делают это. Это уменьшает значение высоты экрана и меняет соотношение. На некоторых устройствах можно получить странные размеры предварительного просмотра (ваш SurfaceView будет немного обрезан)
И чтобы ответить на ваш вопрос, как проверить правильность вашего предварительного просмотра? Затем получите высоту и ширину параметров, которые вы установили:
Ваше установленное соотношение равно высоте / ширине. Если вы хотите, чтобы камера хорошо выглядела на вашем экране, то соотношение высоты / ширины параметров, установленных вами для камеры, должно совпадать с соотношением высоты (без строки состояния) / ширины вашего экрана.
источник
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
.Решение F1Sher хорошо, но иногда не работает. В частности, когда ваш SurfaceView не покрывает весь экран. В этом случае вам необходимо переопределить метод onMeasure (). Я скопировал мой код здесь для вашей справки.
Так как я измерил SurfaceView на основе ширины, то в конце экрана у меня есть небольшой белый промежуток, который я заполнил. Вы можете решить эту проблему, если сохраните высоту и увеличите ширину, умножив ее на коэффициент. Тем не менее, он слегка раздавит SurfaceView.
источник
getOptimalPreviewSize
чтобы это работало на меня. это потому, что ориентация дисплея была установлена на 90? В противном случае, расчет коэффициента не были даже близко (цель была 1,7 , а коэффициенты камеры были меньше , чем 1)ПРИМЕЧАНИЕ: МОЕ РЕШЕНИЕ - ПРОДОЛЖЕНИЕ РЕШЕНИЯ HESAM: https://stackoverflow.com/a/22758359/1718734
Что я адресую: Хесам сказал, что на некоторых телефонах может появиться небольшое пустое пространство, например:
Хесам предложил второе решение, но оно сводит на нет предварительный просмотр. И на некоторых устройствах это сильно искажает.
Итак, как мы можем решить эту проблему. Это просто ... путем умножения пропорций, пока он не заполнит экран. Я заметил, что несколько популярных приложений, таких как Snapchat, WhatsApp и т. Д., Работают одинаково.
Все, что вам нужно сделать, это добавить это в метод onMeasure:
Это вычислит высоту экрана и получит соотношение высоты экрана и высоты mPreviewSize. Затем он умножает ширину и высоту камеры на новое соотношение высоты и соответственно устанавливает измеренный размер.
И следующее, что вы знаете, вы в конечном итоге с этим: D
Это также хорошо работает с фронтальной камерой. Я считаю, что это лучший способ сделать это. Теперь единственное, что осталось для моего приложения, - это сохранить сам предварительный просмотр после нажатия «Захват». Но да, это оно.
источник
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
методе я всегда получаю width = 0 и height = 0;Хорошо, так что я думаю, что нет достаточного ответа для общей проблемы растяжения предварительного просмотра камеры. Или, по крайней мере, я не нашел. Мое приложение также страдало этим синдромом растяжения, и мне потребовалось некоторое время, чтобы найти решение из всех ответов пользователей на этом портале и в Интернете.
Я попробовал решение @ Hesam но оно не сработало, и мой предварительный просмотр камеры был сильно искажен.
Сначала я показываю код моего решения (важные части кода), а затем объясняю, почему я предпринял эти шаги. Есть место для модификаций производительности.
Основная деятельность xml layout:
Предварительный просмотр камеры:
Основное занятие:
Мой комментарий:
Смысл всего этого в том, что , хотя вы вычислить размер оптимальной камеры в
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()
.источник
Здравствуйте, getOptimalPreview (), который здесь не работает, поэтому я хочу поделиться своей версией:
источник
Просто чтобы сделать эту тему более полной, я добавляю свою версию ответа:
Чего я хотел добиться: вид поверхности не должен быть растянут, и он должен охватывать весь экран. Более того, в моем приложении был только ландшафтный режим.
Решение:
Решение является чрезвычайно небольшим расширением решения F1sher:
=> Первый шаг - интегрировать решение F1sher.
=> Теперь в решении F1sher может возникнуть сценарий, когда вид поверхности не покрывает весь экран. Решение состоит в том, чтобы сделать вид поверхности больше размеров экрана, чтобы он охватывал весь экран, для этого:
источник
Я разобрался в чем проблема - именно с изменением ориентации . Если вы измените ориентацию камеры на 90 или 270 градусов, вам нужно поменять местами ширину и высоту поддерживаемых размеров, и все будет в порядке.
Также вид поверхности должен лежать в рамке и иметь центр тяжести.
Вот пример на C # (Xamarin):
Обратите внимание, что параметры камеры должны быть установлены как исходный размер (не поменялся местами), а размер вида поверхности должен поменяться местами.
источник
Я попробовал все решения выше, но ни один из них не работает для меня. В конце концов, я решил это сам, и обнаружил, что это довольно легко. Есть два момента, которые вы должны быть осторожны.
Этот previewSize должен быть одним из поддерживаемых разрешением камеры, которое можно получить, как показано ниже:
обычно один из rawSupportedSize равен разрешению устройства.
Во-вторых, поместите SurfaceView в FrameLayout и установите высоту и ширину макета поверхности в методе SurfaceChanged, как указано выше.
Хорошо, все готово, надеюсь, это поможет вам.
источник
Мои требования: предварительный просмотр камеры должен быть полноэкранным и сохранять соотношение сторон. Решение Hesam и Yoosuf было великолепным, но я почему-то вижу проблему с большим зумом.
Идея та же: иметь центр контейнера предварительного просмотра в родительском элементе и увеличивать ширину или высоту в зависимости от пропорций, пока он не сможет охватить весь экран.
Следует отметить, что размер предварительного просмотра находится в альбомной ориентации, поскольку мы устанавливаем ориентацию экрана.
Контейнер, к которому мы добавим представление SurfaceView:
Добавьте предварительный просмотр в его контейнер с центром в родительском элементе в вашей активности.
Внутри класса CameraPreview:
источник
Вы должны установить cameraView.getLayoutParams (). Height и cameraView.getLayoutParams (). Width в соответствии с желаемым соотношением сторон.
источник
Я отказался от расчетов и просто получил размер вида, в котором я хочу отобразить предварительный просмотр камеры, и установил такой же размер предварительного просмотра камеры (только ширина / высота при повороте) в моей пользовательской реализации SurfaceView:
источник