Pracowałem nad wykonaniem mojej niestandardowej aktywności aparatu w systemie Android, ale podczas obracania aparatu proporcje widoku powierzchni ulegają zepsuciu.
W moim utworze do ćwiczenia ustawiłem układ framelayout, który zawiera widok powierzchni, który wyświetla parametry aparatu.
//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);
Następnie w widoku powierzchni ustawiam parametry kamery do wyświetlania
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();
}
}
Widać, że człowiek LEGO staje się wyższy i chudszy, gdy telefon jest obrócony:
Jak mogę się upewnić, że proporcje obrazu z mojej kamery są prawidłowe?
Odpowiedzi:
Używam tej metody -> na podstawie demonstracji API, aby uzyskać rozmiar podglądu:
Jak widać, musisz wprowadzić szerokość i wysokość ekranu. Ta metoda obliczy współczynnik ekranu na podstawie tych wartości, a następnie z listy obsługiwanych rozmiarów podglądu wybierze najlepszy dla Ciebie spośród dostępnych. Uzyskaj listę supportedPreviewSize w miejscu, w którym obiekt Camera nie jest null, za pomocą
A następnie w onMeasure możesz uzyskać optymalny podgląd rozmiaru:
A potem (w moim kodzie w metodzie surfaceChanged, tak jak powiedziałem, używam struktury API Demos kodu CameraActivity, możesz wygenerować ją w Eclipse):
I jedna wskazówka dla Ciebie, ponieważ zrobiłem prawie taką samą aplikację jak Ty. Dobrą praktyką w przypadku aktywności kamery jest ukrycie paska stanu. Aplikacje takie jak Instagram robią to. Zmniejsza wartość wysokości ekranu i zmienia wartość współczynnika. Na niektórych urządzeniach można uzyskać dziwne rozmiary podglądu (Twój SurfaceView zostanie trochę przycięty)
A odpowiadając na pytanie, jak sprawdzić, czy współczynnik podglądu jest poprawny? Następnie uzyskaj wysokość i szerokość parametrów, które ustawiasz w:
Twój ustawiony stosunek jest równy wysokości / szerokości. Jeśli chcesz, aby kamera dobrze wyglądała na ekranie, stosunek wysokości do szerokości parametrów, które ustawisz dla kamery, musi być taki sam, jak stosunek wysokości (bez paska stanu) do szerokości ekranu.
źródło
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
.Rozwiązanie F1Sher jest fajne, ale czasami nie działa. Szczególnie, gdy SurfaceView nie obejmuje całego ekranu. W takim przypadku musisz nadpisać metodę onMeasure (). Skopiowałem tutaj mój kod w celach informacyjnych.
Ponieważ zmierzyłem surfaceView na podstawie szerokości, na końcu ekranu mam małą białą lukę, którą wypełniłem zgodnie z projektem. Możesz rozwiązać ten problem, jeśli zachowasz wysokość i zwiększysz szerokość, mnożąc ją przez współczynnik. Jednak spowoduje to nieznaczne zgniecenie surfaceView.
źródło
getOptimalPreviewSize
aby to zadziałało. czy to dlatego, że orientacja wyświetlania została ustawiona na 90? W przeciwnym razie, obliczenia ratio nie były nawet blisko (target wynosił 1,7 i proporcje były mniej niż kamera 1)UWAGA: MOJE ROZWIĄZANIE TO KONTYNUACJA ROZWIĄZANIA HESAM: https://stackoverflow.com/a/22758359/1718734
Do czego się zwracam: Hesam powiedział, że na niektórych telefonach może pojawić się mała biała przestrzeń, na przykład:
Hesam zasugerował drugie rozwiązanie, ale to ogranicza podgląd. A na niektórych urządzeniach mocno zniekształca.
Jak więc rozwiązać ten problem. Jest to proste ... mnożąc proporcje, aż wypełni ekran. Zauważyłem, że kilka popularnych aplikacji, takich jak Snapchat, WhatsApp itp., Działa w ten sam sposób.
Wszystko, co musisz zrobić, to dodać to do metody onMeasure:
To obliczy wysokość ekranu i pobierze stosunek wysokości ekranu do wysokości mPreviewSize. Następnie mnoży szerokość i wysokość kamery przez nowy współczynnik wysokości i odpowiednio ustawia zmierzony wymiar.
I następna rzecz, którą wiesz, kończy się na tym: D
Działa to również dobrze z przednim aparatem. Uważam, że to najlepszy sposób, aby to osiągnąć. Teraz jedyne, co pozostało dla mojej aplikacji, to zapisanie samego podglądu po kliknięciu przycisku „Przechwyć”. Ale tak, to jest to.
źródło
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
metodzie zawsze otrzymuję szerokość = 0 i wysokość = 0;OK, więc myślę, że nie ma wystarczającej odpowiedzi na ogólny problem z rozciąganiem podglądu kamery. A przynajmniej nie znalazłem. Moja aplikacja również cierpiała na syndrom rozciągania i zajęło mi trochę czasu, aby wspólnie znaleźć rozwiązanie ze wszystkich odpowiedzi użytkowników w tym portalu i internecie.
Wypróbowałem rozwiązanie @ Hesam, ale nie zadziałało i mój podgląd kamery został znacznie zniekształcony.
Najpierw pokazuję kod mojego rozwiązania (ważne części kodu), a następnie wyjaśniam, dlaczego podjąłem te kroki. Jest miejsce na modyfikacje wydajności.
Układ XML głównej aktywności:
Podgląd aparatu:
Główna aktywność:
Mój komentarz:
Punktem wszystkim jest to, że chociaż można obliczyć wielkość optymalna kamery w
getOptimalPreviewSize()
wybrać tylko najbliższy proporcje dopasowane do rozmiaru ekranu. Więc jeśli stosunek nie jest dokładnie taki sam, podgląd zostanie rozciągnięty.Dlaczego się rozciągnie? Ponieważ podgląd kamery FrameLayout jest ustawiony w pliku layout.xml na match_parent pod względem szerokości i wysokości. Dlatego podgląd rozciąga się na pełny ekran.
To, co należy zrobić, to ustawić szerokość i wysokość układu podglądu kamery, aby pasowały do wybranego współczynnika rozmiaru kamery , aby podgląd zachował proporcje i nie zniekształcił.
Próbowałem użyć
CameraPreview
klasy, aby wykonać wszystkie obliczenia i zmiany układu, ale nie mogłem tego rozgryźć. Próbowałem zastosować to rozwiązanie , aleSurfaceView
nie rozpoznajegetChildCount ()
lubgetChildAt (int index)
. Myślę, że w końcu udało mi się to zadziałać z odniesieniem domaLayoutPreview
, ale źle się zachowywał i zastosowałem ustawiony współczynnik do całej mojej aplikacji i tak się stało po zrobieniu pierwszego zdjęcia. Więc odpuściłem i przeniosłem modyfikacje układu doMainActivity
.W
CameraPreview
zmieniłemprSupportedPreviewSizes
igetOptimalPreviewSize()
do publiczności , dzięki czemu można go używać wMainActivity
. Następnie potrzebowałem wymiarów wyświetlacza (bez paska nawigacji / stanu, jeśli taki istnieje) i wybrałem optymalny rozmiar kamery . Próbowałem uzyskać rozmiar RelativeLayout (lub FrameLayout) zamiast rozmiaru wyświetlacza, ale zwracał wartość zerową. To rozwiązanie nie zadziałało. Układ ma swoją wartość poonWindowFocusChanged
(zaznaczony w dzienniku).Mam więc swoje metody obliczania wymiarów układu, aby pasowały do proporcji wybranego rozmiaru aparatu. Teraz wystarczy ustawić
LayoutParams
układ podglądu aparatu. Zmień szerokość, wysokość i wyśrodkuj w nadrzędnym.Istnieją dwie możliwości obliczenia wymiarów podglądu. Albo chcesz, aby pasował do ekranu z czarnymi paskami (jeśli windowBackground ma wartość null) po bokach lub u góry / u dołu. Lub chcesz, aby podgląd był powiększony do pełnego ekranu . Zostawiłem komentarz z większą ilością informacji w
calcCamPrevDimensions()
.źródło
Cześć, getOptimalPreview (), który jest tutaj, nie działał dla mnie, więc chcę udostępnić moją wersję:
źródło
Aby uzupełnić ten wątek, dodaję moją wersję odpowiedzi:
Co chciałem osiągnąć: widok powierzchni nie powinien być rozciągany, a powinien obejmować cały ekran, ponadto w mojej aplikacji był tylko tryb krajobrazu.
Rozwiązanie:
Rozwiązaniem jest niezwykle małe rozszerzenie rozwiązania F1sher:
=> Pierwszym krokiem jest integracja rozwiązania F1sher.
=> Teraz w rozwiązaniu F1sher może pojawić się scenariusz, w którym widok powierzchni nie obejmuje całego ekranu.Rozwiązaniem jest, aby widok powierzchni był większy niż wymiary ekranu, tak aby obejmował cały ekran, w tym celu:
źródło
Zrozumiałem, w czym problem - to ze zmianami orientacji . Jeśli zmienisz orientację kamery na 90 lub 270 stopni, musisz zamienić szerokość i wysokość obsługiwanych rozmiarów i wszystko będzie w porządku.
Również widok powierzchni powinien leżeć w układzie ramy i mieć środek ciężkości.
Oto przykład w C # (Xamarin):
Zwróć uwagę, że parametry kamery powinny być ustawione jako oryginalne (nie zamienione), a rozmiar widoku powierzchni powinien zostać zamieniony.
źródło
Wypróbowałem wszystkie powyższe rozwiązania, ale żadne z nich nie działa dla mnie. w końcu rozwiązałem to sam i stwierdziłem, że jest to całkiem łatwe. trzeba uważać na dwa punkty.
ten rozmiar podglądu musi być jedną z obsługiwanych przez kamerę rozdzielczości, którą można uzyskać jak poniżej:
zwykle jeden z rawSupportedSize jest równy rozdzielczości urządzenia.
Po drugie, umieść SurfaceView w FrameLayout i ustaw wysokość i szerokość układu powierzchni w metodzie surfaceChanged, jak powyżej
OK, gotowe, mam nadzieję, że to ci pomoże.
źródło
Moje wymagania są takie, że podgląd z kamery musi być pełnoekranowy i zachować proporcje. Rozwiązanie Hesama i Yoosufa było świetne, ale z jakiegoś powodu widzę problem z dużym zoomem.
Pomysł jest taki sam, umieść środek kontenera podglądu w nadrzędnym i zwiększaj szerokość lub wysokość w zależności od współczynników proporcji, aż pokryje cały ekran.
Należy zwrócić uwagę na to, że rozmiar podglądu jest w poziomie, ponieważ ustawiamy orientację wyświetlania.
Kontener, do którego dodamy widok SurfaceView:
Dodaj podgląd do jego kontenera ze środkiem w rodzicu w swojej aktywności.
W klasie CameraPreview:
źródło
Musisz ustawić cameraView.getLayoutParams (). Height i cameraView.getLayoutParams (). Width zgodnie z wymaganym współczynnikiem proporcji.
źródło
Zrezygnowałem z obliczeń i po prostu uzyskałem rozmiar widoku, w którym chcę wyświetlać podgląd kamery i ustawiłem ten sam rozmiar podglądu kamery (po prostu odwrócił szerokość / wysokość z powodu obrotu) w mojej niestandardowej implementacji SurfaceView:
źródło