Eu tenho um UIImageView
interior UIScrollView
que eu uso para aplicar zoom e rolagem. Se a imagem / o conteúdo da exibição de rolagem for maior que a exibição de rolagem, tudo funcionará bem. No entanto, quando a imagem se torna menor que a exibição de rolagem, ela fica no canto superior esquerdo da exibição de rolagem. Gostaria de mantê-lo centralizado, como o aplicativo Fotos.
Alguma idéia ou exemplo sobre como manter o conteúdo do UIScrollView
centro quando menor?
Estou trabalhando com o iPhone 3.0.
O código a seguir quase funciona. A imagem retornará ao canto superior esquerdo se eu apertá-la depois de atingir o nível mínimo de zoom.
- (void)loadView {
[super loadView];
// set up main scroll view
imageScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
[imageScrollView setBackgroundColor:[UIColor blackColor]];
[imageScrollView setDelegate:self];
[imageScrollView setBouncesZoom:YES];
[[self view] addSubview:imageScrollView];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"WeCanDoIt.png"]];
[imageView setTag:ZOOM_VIEW_TAG];
[imageScrollView setContentSize:[imageView frame].size];
[imageScrollView addSubview:imageView];
CGSize imageSize = imageView.image.size;
[imageView release];
CGSize maxSize = imageScrollView.frame.size;
CGFloat widthRatio = maxSize.width / imageSize.width;
CGFloat heightRatio = maxSize.height / imageSize.height;
CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
[imageScrollView setMinimumZoomScale:initialZoom];
[imageScrollView setZoomScale:1];
float topInset = (maxSize.height - imageSize.height) / 2.0;
float sideInset = (maxSize.width - imageSize.width) / 2.0;
if (topInset < 0.0) topInset = 0.0;
if (sideInset < 0.0) sideInset = 0.0;
[imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}
/************************************** NOTE **************************************/
/* The following delegate method works around a known bug in zoomToRect:animated: */
/* In the next release after 3.0 this workaround will no longer be necessary */
/**********************************************************************************/
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
[scrollView setZoomScale:scale+0.01 animated:NO];
[scrollView setZoomScale:scale animated:NO];
// END Bug workaround
CGSize maxSize = imageScrollView.frame.size;
CGSize viewSize = view.frame.size;
float topInset = (maxSize.height - viewSize.height) / 2.0;
float sideInset = (maxSize.width - viewSize.width) / 2.0;
if (topInset < 0.0) topInset = 0.0;
if (sideInset < 0.0) sideInset = 0.0;
[imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}
Respostas:
Eu tenho uma solução muito simples! Tudo o que você precisa é atualizar o centro da sua subvisão (visualização de imagem) enquanto amplia o ScrollViewDelegate. Se a imagem ampliada for menor que a visualização de rolagem, ajuste o subview.center else center é (0,0).
fonte
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentInset.left - scrollView.contentInset.right - scrollView.contentSize.width) * 0.5, 0.0); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom - scrollView.contentSize.height) * 0.5, 0.0);
zoomToRect:
. O uso dacontentInset
abordagem funciona melhor se você precisar dessa funcionalidade. Consulte petersteinberger.com/blog/2013/how-to-center-uiscrollview para obter mais detalhes.A resposta de @ EvelynCordner foi a que funcionou melhor no meu aplicativo. Muito menos código do que as outras opções também.
Aqui está a versão Swift, se alguém precisar:
fonte
Ok, eu estive lutando contra isso nos últimos dois dias e, finalmente, tendo chegado a uma solução bastante confiável (até agora ...), achei que deveria compartilhá-lo e evitar outras dores. :) Se você encontrar algum problema com esta solução, grite!
Eu basicamente passei pelo que todo mundo tem: pesquisando no StackOverflow, os Fóruns de desenvolvedores da Apple, procurei o código por three20, ScrollingMadness, ScrollTestSuite, etc. Tentei ampliar o quadro UIImageView, jogando com o deslocamento e / ou inserções do UIScrollView do ViewController, etc., mas nada funcionou muito bem (como todo mundo descobriu também).
Depois de dormir, tentei alguns ângulos alternativos:
Com esse método UIScrollView de subclasse, estou substituindo o mutador contentOffset, para que ele não esteja configurando {0,0} quando a imagem é dimensionada menor que a viewport - em vez disso, está configurando o deslocamento para que a imagem seja mantida centralizada na viewport. Até agora, parece sempre funcionar. Verifiquei-o com imagens amplas, altas, minúsculas e grandes e não possui o problema "funciona, mas aperte com o zoom mínimo".
Fiz upload de um projeto de exemplo no github que usa essa solução, você pode encontrá-lo aqui: http://github.com/nyoron/NYOBetterZoom
fonte
anOffset.y = -(scrollViewSize.height - zoomViewSize.height) / 2.0
paraanOffset.y = (-(scrollViewSize.height - zoomViewSize.height) / 2.0) + 10;
Esse código deve funcionar na maioria das versões do iOS (e foi testado para funcionar na versão 3.1 acima).
É baseado no código WWDC da Apple para o fotocoller.
Adicione o seguinte à sua subclasse de UIScrollView e substitua tileContainerView pela exibição que contém sua imagem ou blocos:
fonte
UIScrollView
abordagem da subclasse parece preferível: é invocada quando a exibição é exibida pela primeira vez + continuamente enquanto o zoom está em andamento (enquantoscrollViewDidZoom
é invocado apenas uma vez por rolagem e após o fato)Para uma solução mais adequada para exibições de rolagem que usam o layout automático, use inserções de conteúdo da exibição de rolagem em vez de atualizar os quadros das sub-visualizações da exibição de rolagem.
fonte
UIView
que está dentro doUIScrollview
para o mesmo centro (view.center = scrollview.center;
) e, em seguida, noscrollViewDidZoom
conjunto doview.frame.origin
x
ey
para0
novamente.dispatch_async
a fila principal naviewWillAppear
qual chamoscrollViewDidZoom:
na minha visualização principal de rolagem. Isso faz a exibição aparecer com imagens centralizadas.viewDidLayoutSubviews
para garantir que ele esteja configurado corretamente quando a exibição aparecer pela primeira vez.Atualmente, estou subclassificando
UIScrollView
e substituindosetContentOffset:
para ajustar o deslocamento com base emcontentSize
. Funciona com pitada e zoom programático.Além de ser curto e agradável, esse código produz um zoom muito mais suave que a solução @Erdemus. Você pode vê-lo em ação na demonstração do RMGallery .
fonte
Passei um dia lutando com esse problema e acabei implementando o scrollViewDidEndZooming: withView: atScale: da seguinte maneira:
Isso garante que, quando a imagem for menor que a tela, ainda haja espaço suficiente ao redor para que você possa posicioná-la no local exato que deseja.
(supondo que seu UIScrollView contenha um UIImageView para manter a imagem)
Basicamente, o que isso faz é verificar se a largura / altura da visualização da imagem é menor que a largura / altura da tela e, em caso afirmativo, criar uma inserção de metade da largura / altura da tela (você provavelmente poderá aumentar isso se quiser que a imagem sair dos limites da tela).
Observe que, como esse é um método UIScrollViewDelegate , não se esqueça de adicioná-lo à declaração do seu controlador de exibição, para evitar problemas de compilação.
fonte
A Apple lançou os vídeos da sessão da WWDC de 2010 para todos os membros do programa de desenvolvedor do iphone. Um dos tópicos discutidos é como eles criaram o aplicativo de fotos !!! Eles criam um aplicativo muito semelhante passo a passo e disponibilizam todo o código gratuitamente.
Também não usa API privada. Não posso colocar nenhum código aqui por causa do contrato de não divulgação, mas aqui está um link para o download do código de amostra. Você provavelmente precisará fazer login para obter acesso.
http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645
E, aqui está um link para a página WWDC do iTunes:
http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj
fonte
Ok, esta solução está funcionando para mim. Eu tenho uma subclasse de
UIScrollView
com uma referência aoUIImageView
que está exibindo. Sempre que oUIScrollView
zoom é aplicado, a propriedade contentSize é ajustada. É no levantador que eu dimensionoUIImageView
adequadamente e também ajusto sua posição central.Sempre eu coloco a imagem no
UIScrollView
redimensiono. OUIScrollView
no scrollview também é uma classe personalizada que eu criei.Com esses dois métodos, sou capaz de ter uma visão que se comporta exatamente como o aplicativo de fotos.
fonte
A maneira como fiz isso é adicionar uma visão extra à hierarquia:
Dê
UIView
a mesma proporção que a suaUIScrollView
e centralize-aUIImageView
nisso.fonte
Sei que algumas das respostas acima estão corretas, mas só quero dar minha resposta com algumas explicações. Os comentários farão você entender por que fazemos isso.
Quando carrego o scrollView pela primeira vez, escrevo o código a seguir para torná-lo central, observe que definimos
contentOffset
primeiro e, em seguida,contentInset
Em seguida, quando aperto o vContent, escrevo o código a seguir para torná-lo central.
fonte
Se
contentInset
não for necessário para mais nada, ele pode ser usado para centralizar o conteúdo do scrollview.Vantagem, se essa abordagem for a que você ainda pode usar
contentLayoutGuide
para colocar o conteúdo dentro do scrollviewou simplesmente arraste e solte o conteúdo no Interface Builder do Xcode.
fonte
Você pode observar a
contentSize
propriedade do UIScrollView (usando observação de valor-chave ou similar) e ajustar automaticamentecontentInset
sempre que ascontentSize
alterações forem menores que o tamanho da exibição de rolagem.fonte
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
(descrito em developer.apple.com/iphone/library/documentation/UIKit/… ), mas eu prefiro observarcontentSize
porque, caso contrário, você acaba descartando a nova escala de zoom e localizando-a de qualquer maneira. (A menos que você pode retirar um pouco de matemática incrível com base nos tamanhos relativos dos seus pontos de vista.)Uma maneira elegante de centralizar o conteúdo
UISCrollView
é essa.Adicione um observador ao contentSize do seu
UIScrollView
, para que esse método seja chamado sempre que o conteúdo for alterado ...Agora no seu método de observador:
Você deve mudar o
[pointer viewWithTag:100]
. Substitua pela sua exibição de conteúdoUIView
.imageGallery
apontando para o tamanho da sua janela.Isso corrigirá o centro do conteúdo sempre que seu tamanho for alterado.
NOTA: A única maneira de esse conteúdo não funcionar muito bem é com a funcionalidade de zoom padrão do
UIScrollView
.fonte
Esta é a minha solução para esse problema, que funciona muito bem para qualquer tipo de exibição dentro de uma exibição de rolagem.
fonte
Existem muitas soluções aqui, mas eu arriscaria colocar aqui a minha. É bom por dois motivos: não atrapalha a experiência de zoom, como faria com a atualização do quadro de exibição de imagem em andamento, e também respeita as inserções de exibição de rolagem originais (por exemplo, definidas no xib ou no storyboard para manuseio gracioso de barras de ferramentas semitransparentes etc.) .
Primeiro, defina um pequeno auxiliar:
Para manter inserções originais, campo definido:
E em algum lugar no viewDidLoad preencha:
Para colocar o UIImageView no UIScrollView (assumindo que o próprio UIImage esteja em loadedImage var):
scrollViewDidZoom: de UIScrollViewDelegate para essa visualização de rolagem:
Um finalmente, centralizando-se:
Ainda não testei a mudança de orientação (ou seja, a reação adequada para redimensionar o próprio UIScrollView), mas a correção deve ser relativamente fácil.
fonte
Você descobrirá que a solução publicada pela Erdemus funciona, mas… Existem alguns casos em que o método scrollViewDidZoom não é chamado e sua imagem fica presa no canto superior esquerdo. Uma solução simples é chamar explicitamente o método quando você exibe inicialmente uma imagem, assim:
Em muitos casos, você pode invocar esse método duas vezes, mas esta é uma solução mais limpa do que algumas das outras respostas neste tópico.
fonte
O Photo Scroller Example da Apple faz exatamente o que você está procurando. Coloque isso na sua subclasse UIScrollView e altere _zoomView para ser seu UIImageView.
Código de exemplo do Photo Scroller da Apple
fonte
Para fazer a animação fluir bem, defina
e use esta função (localizando o centro usando o método nesta resposta )
Isso cria o efeito de salto, mas não envolve movimentos bruscos de antemão.
fonte
Apenas a resposta aprovada rapidamente, mas sem subclasse usando o delegado
fonte
Caso o seu imageView interno tenha uma largura inicial específica (por exemplo, 300) e você queira centralizar sua largura apenas no zoom menor que a largura inicial, isso também poderá ajudá-lo.
fonte
Aqui está a maneira atual de fazer esse trabalho. É melhor, mas ainda não é perfeito. Tente configurar:
para corrigir o problema com a visualização não centralizada quando em
minZoomScale
.Além disso, faço o seguinte para impedir que a imagem fique do lado após diminuir o zoom.
fonte
Ok, acho que encontrei uma solução muito boa para esse problema. O truque é reajustar constantemente o
imageView's
quadro. Acho que isso funciona muito melhor do que ajustar constantemente ocontentInsets
oucontentOffSets
. Eu tive que adicionar um pouco de código extra para acomodar as imagens retrato e paisagem.Aqui está o código:
fonte
Apenas desative a paginação, para que funcione bem:
fonte
Eu tive o mesmo problema. Aqui está como eu resolvi
Esse código deve ser chamado como resultado de
scrollView:DidScroll:
fonte
Embora a questão seja um pouco antiga, o problema ainda existe. Eu o resolvi no Xcode 7 criando a restrição de espaço vertical do item mais alto (neste caso, o
topLabel
) para os superViews (thescrollView
) top anIBOutlet
e depois recalculando sua constante sempre que o conteúdo muda, dependendo da altura das subvisões do scrollView (topLabel
ebottomLabel
)fonte