Eu tenho trabalhado na criação da minha atividade de câmera personalizada no Android, mas ao girar a câmera, a proporção da visualização da superfície fica confusa.
No meu trabalho para a atividade, defino o layout da moldura que mantém a visualização da superfície que exibe os parâmetros da câmera.
//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);
Em seguida, na visualização Surface, defino os parâmetros da câmera a serem exibidos
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();
}
}
Você pode ver que o homem LEGO cresce mais alto e mais fino quando o telefone é girado:
Como posso garantir que a proporção da visualização da minha câmera esteja correta?
android
android-camera
surfaceview
preview
aspect-ratio
cientifico
fonte
fonte
Respostas:
Estou usando esse método -> com base nas demonstrações da API para obter meu tamanho de visualização:
Como você pode ver, é necessário inserir a largura e a altura da tela. Este método calculará a proporção da tela com base nesses valores e, a partir da lista de supportedPreviewSizes, escolherá o melhor para você dentre os disponíveis. Obtenha sua lista supportedPreviewSize no local em que o objeto Câmera não é nulo usando
E, em seguida, no onMeasure, você pode obter sua visualização ideal
E então (no meu código no método surfaceChanged, como eu disse que estou usando a estrutura API Demos do código CameraActivity, você pode gerá-lo no Eclipse):
E uma dica para você, porque eu fiz quase o mesmo aplicativo como você. A boa prática para a atividade da câmera é ocultar a barra de status. Aplicativos como o Instagram estão fazendo isso. Reduz o valor da altura da tela e altera o valor da proporção. É possível obter tamanhos de visualização estranhos em alguns dispositivos (o SurfaceView será cortado um pouco)
E para responder sua pergunta, como verificar se a taxa de visualização está correta? Em seguida, obtenha a altura e a largura dos parâmetros definidos:
sua proporção definida é igual a altura / largura. Se você deseja que a câmera tenha uma boa aparência na tela, a proporção de altura / largura dos parâmetros configurados para a câmera deve ser a mesma que a proporção de altura (menos barra de status) / largura da tela.
fonte
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
.A solução da F1Sher é boa, mas às vezes não funciona. Particularmente, quando o seu surfaceView não cobre a tela inteira. Nesse caso, você precisa substituir o método onMeasure (). Copiei meu código aqui para sua referência.
Como medi o surfaceView com base na largura, tenho um pouco de espaço branco no final da tela que preenchai por design. Você poderá corrigir esse problema se mantiver a altura e aumentar a largura multiplicando-a pela proporção. No entanto, ele irá pressionar o SurfaceView levemente.
fonte
getOptimalPreviewSize
para que isso funcionasse para mim. isso ocorre porque a orientação da tela foi definida como 90? Caso contrário, os cálculos da proporção não estavam nem perto (o objetivo era 1,7 e a proporção da câmera era menor que 1)NOTA: MINHA SOLUÇÃO É UMA CONTINUAÇÃO DA SOLUÇÃO DE HESAM: https://stackoverflow.com/a/22758359/1718734
O que eu dirijo: Hesam disse que há um pequeno espaço em branco que pode aparecer em alguns telefones, como este:
Hesam sugeriu uma segunda solução, mas isso estraga a visualização. E em alguns dispositivos, isso distorce bastante.
Então, como podemos resolver esse problema. É simples ... multiplicando as proporções até preencher a tela. Eu notei que vários aplicativos populares como Snapchat, WhatsApp etc. funcionam da mesma maneira.
Tudo o que você precisa fazer é adicionar isso ao método onMeasure:
Isso calculará a altura da tela e obterá a proporção entre a altura da tela e a altura do mPreviewSize. Em seguida, multiplica a largura e a altura da câmera pela nova taxa de altura e define a dimensão medida de acordo.
E a próxima coisa que você sabe, você acaba com isso: D
Isso também funciona bem com a câmera frontal. Eu acredito que esta é a melhor maneira de fazer isso. Agora, a única coisa que resta para o meu aplicativo é salvar a visualização em si mesma ao clicar em "Capturar". Mas sim, é isso.
fonte
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
método, sempre obtenho largura = 0 e altura = 0;OK, então eu acho que não há resposta suficiente para o problema geral de alongamento da visualização da câmera. Ou pelo menos não encontrei um. Meu aplicativo também sofreu essa síndrome de alongamento e demorei um pouco para encontrar uma solução de todas as respostas dos usuários neste portal e na Internet.
Eu tentei a solução da @ Hesam mas ela não funcionou e deixou a visualização da câmera distorcida.
Primeiro, mostro o código da minha solução (as partes importantes do código) e depois explico por que tomei essas medidas. Há espaço para modificações de desempenho.
Layout xml da atividade principal:
Visualização da câmera:
Atividade principal:
Meu comentário:
O ponto de tudo isso é que, embora você calcular o tamanho da câmera ideal em
getOptimalPreviewSize()
você só escolher o rácio mais próximo para caber na tela. Portanto, a menos que a proporção seja exatamente a mesma, a visualização será ampliada.Por que isso vai esticar? Como a visualização da câmera do FrameLayout está definida em layout.xml para corresponder_parent em largura e altura. É por isso que a visualização será ampliada para tela cheia.
O que precisa ser feito é definir a largura e a altura do layout da visualização da câmera para corresponder à proporção de tamanho da câmera escolhida , para que a visualização mantenha sua proporção e não distorça.
Tentei usar a
CameraPreview
classe para fazer todos os cálculos e alterações de layout, mas não consegui descobrir. Eu tentei aplicar esta solução , masSurfaceView
não reconhecegetChildCount ()
ougetChildAt (int index)
. Acho que consegui trabalhar eventualmente com uma referência amaLayoutPreview
, mas estava se comportando mal e aplicou a proporção definida para todo o meu aplicativo e o fez depois que a primeira foto foi tirada. Então eu deixei para lá e mudei as modificações de layout para oMainActivity
.Em
CameraPreview
mudeiprSupportedPreviewSizes
egetOptimalPreviewSize()
para público para que eu possa usá-loMainActivity
. Então eu precisei das dimensões da tela (menos a barra de navegação / status, se houver) e escolhi o tamanho ideal da câmera . Tentei obter o tamanho do RelativeLayout (ou FrameLayout) em vez do tamanho da exibição, mas ele estava retornando valor zero. Esta solução não funcionou para mim. O layout obteve seu valor apósonWindowFocusChanged
(verificado no log).Então, eu tenho meus métodos para calcular as dimensões do layout para corresponder à proporção do tamanho de câmera escolhido. Agora você só precisa definir
LayoutParams
o layout de visualização da câmera. Mude a largura, altura e centralize-a no pai.Existem duas opções de como calcular as dimensões da visualização. Você deseja que ele se ajuste à tela com barras pretas (se windowBackground estiver definido como nulo) nas laterais ou na parte superior / inferior. Ou você deseja que a visualização seja ampliada para tela cheia . Deixei um comentário com mais informações em
calcCamPrevDimensions()
.fonte
Olá, o getOptimalPreview () que está aqui não funcionou para mim, por isso quero compartilhar minha versão:
fonte
Apenas para tornar este tópico mais completo, estou adicionando minha versão da resposta:
O que eu queria alcançar: a visualização da superfície não deve ser esticada e deve cobrir a tela inteira. Além disso, havia apenas um modo paisagem no meu aplicativo.
Solução:
A solução é uma extensão extremamente pequena para a solução F1sher:
=> O primeiro passo é integrar a solução F1sher.
=> Agora, pode surgir um cenário na solução do F1sher quando a visualização da superfície não cobre a tela inteira. A solução é tornar a visualização da superfície maior que as dimensões da tela para que cubra a tela inteira, para:
fonte
Eu descobri qual é o problema - é com as mudanças de orientação . Se você alterar a orientação da câmera para 90 ou 270 graus, precisará trocar a largura e a altura dos tamanhos suportados e tudo ficará bem.
A visualização da superfície também deve estar em um layout de quadro e ter gravidade central.
Aqui está um exemplo em C # (Xamarin):
Preste atenção que os parâmetros da câmera devem ser definidos como tamanho original (não trocados) e o tamanho da visualização da superfície deve ser trocada.
fonte
Eu tentei toda a solução acima, mas nenhum deles funciona para mim. Finalmente eu mesmo resolvi e acho que é bem fácil. Existem dois pontos que você precisa ter cuidado.
este previewSize deve ser uma das resoluções suportadas pela câmera, que pode ser obtida abaixo:
geralmente um dos rawSupportedSize é igual à resolução do dispositivo.
Segundo, coloque o SurfaceView em um FrameLayout e defina a altura e a largura do layout da superfície no método surfaceChanged como acima
Ok, pronto, espero que isso possa ajudá-lo.
fonte
Meus requisitos são que a visualização da câmera precise ter tela cheia e manter a proporção. A solução de Hesam e Yoosuf foi ótima, mas vejo um problema de zoom alto por algum motivo.
A idéia é a mesma, ter o centro de contêiner de visualização no pai e aumentar a largura ou a altura, dependendo das proporções, até que possa cobrir a tela inteira.
Uma coisa a observar é que o tamanho da visualização está em paisagem porque definimos a orientação da exibição.
O contêiner ao qual adicionaremos a visualização SurfaceView:
Adicione a visualização ao seu contêiner com o centro no pai na sua atividade.
Dentro da classe CameraPreview:
fonte
Você deve definir cameraView.getLayoutParams (). Height e cameraView.getLayoutParams (). Width de acordo com a proporção que deseja.
fonte
Eu desisti dos cálculos e simplesmente obtive o tamanho da visualização em que eu quero que a visualização da câmera seja exibida e defina o tamanho da visualização da mesma (apenas a largura / altura invertida devido à rotação) na minha implementação personalizada do SurfaceView:
fonte