É possível centralizar o conteúdo em um uiscrollView como o aplicativo de fotos da Apple?

StackOverflow https://stackoverflow.com/questions/1496015

Pergunta

Estou lutando com esse problema há algum tempo e parece não haver uma resposta clara. Por favor, deixe -me saber se alguém descobriu isso.

Eu quero exibir uma foto em um UIScrollView que está centrado na tela (a imagem pode estar na orientação de retrato ou paisagem).

Quero poder aumentar o zoom e panificar a imagem apenas para a borda da imagem, como no aplicativo Fotos.

Eu tentei alterar o contentInset no viewDidEndZooming Método e esse tipo de truque, mas há várias falhas.

Eu também tentei fazer o imageView do mesmo tamanho que o scrollView e centralizar a imagem lá. O problema é que, quando você amplia o zoom, você pode rolar por todo imageView e parte da imagem pode rolar a visualização.

Encontrei um post semelhante aqui e dei a minha melhor solução alternativa, mas nenhuma resposta real foi encontrada:

UISCROLLVIEW com UIImageView central, como o aplicativo Fotos

Foi útil?

Solução 3

Aqui está a melhor solução que eu poderia apresentar para esse problema. O truque é reajustar constantemente o quadro do ImageView. Acho que isso funciona muito melhor do que ajustar constantemente os contentinsets ou o ContentOffSets. Eu tive que adicionar um pouco de código extra para acomodar imagens de retrato e paisagem.

Se alguém puder encontrar uma maneira melhor de fazê -lo, eu adoraria ouvi -lo.

Aqui está o código:

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {

CGSize screenSize = [[self view] bounds].size;

if (myScrollView.zoomScale <= initialZoom +0.01) //This resolves a problem with the code not working correctly when zooming all the way out.
{
    imageView.frame = [[self view] bounds];
    [myScrollView setZoomScale:myScrollView.zoomScale +0.01];
}

if (myScrollView.zoomScale > initialZoom)
{
    if (CGImageGetWidth(temporaryImage.CGImage) > CGImageGetHeight(temporaryImage.CGImage)) //If the image is wider than tall, do the following...
    {
            if (screenSize.height >= CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is greater than the zoomed height of the image do the following...
            {
                    imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), 368);
            }
            if (screenSize.height < CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is less than the zoomed height of the image do the following...
            {
                    imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]);
            }
    }
    if (CGImageGetWidth(temporaryImage.CGImage) < CGImageGetHeight(temporaryImage.CGImage)) //If the image is taller than wide, do the following...
    {
            CGFloat portraitHeight;
            if (CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale] < 368)
            { portraitHeight = 368;}
            else {portraitHeight = CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale];}

            if (screenSize.width >= CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is greater than the zoomed width of the image do the following...
            {
                    imageView.frame = CGRectMake(0, 0, 320, portraitHeight);
            }
            if (screenSize.width < CGImageGetWidth (temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is less than the zoomed width of the image do the following...
            {
                    imageView.frame = CGRectMake(0, 0, CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale], portraitHeight);
            }
    }
    [myScrollView setZoomScale:myScrollView.zoomScale -0.01];
}

Aqui está como eu calcule a escala Min Zoom no método ViewDidload.

CGSize photoSize = [temporaryImage size];
CGSize screenSize = [[self view] bounds].size;

CGFloat widthRatio = screenSize.width / photoSize.width;
CGFloat heightRatio = screenSize.height / photoSize.height;
initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
[myScrollView setMinimumZoomScale:initialZoom];
[myScrollView setZoomScale:initialZoom];
[myScrollView setMaximumZoomScale:3.0];

Outras dicas

Uma maneira elegante de centralizar o conteúdo de UISCrollView é isto.

Adicione um observador ao contentsize do seu UIScrollView, então esse método será chamado toda vez que a mudança de conteúdo ...

[myScrollView addObserver:delegate 
               forKeyPath:@"contentSize"
                  options:(NSKeyValueObservingOptionNew) 
                  context:NULL];

Agora, no seu método observador:

- (void)observeValueForKeyPath:(NSString *)keyPath   ofObject:(id)object   change:(NSDictionary *)change   context:(void *)context { 

    // Correct Object Class.
    UIScrollView *pointer = object;

    // Calculate Center.
    CGFloat topCorrect = ([pointer bounds].size.height - [pointer viewWithTag:100].bounds.size.height * [pointer zoomScale])  / 2.0 ;
            topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );

    topCorrect = topCorrect - (  pointer.frame.origin.y - imageGallery.frame.origin.y );

    // Apply Correct Center.
    pointer.center = CGPointMake(pointer.center.x,
                                 pointer.center.y + topCorrect ); }
  • Você deve mudar o [pointer viewWithTag:100]. Substitua por sua visão de conteúdo UIView.

    • Também mude imageGallery apontando para o tamanho da sua janela.

Isso corrigirá o centro do conteúdo toda vez que sua mudança de tamanho.

NOTA: A única maneira de esse conteúdo não funciona muito bem é com a funcionalidade de zoom padrão do UIScrollView.

Esse código deve funcionar na maioria das versões do iOS (e foi testado para trabalhar em 3.1 para cima).

É baseado no código da Apple WWDC para o aplicativo Photoscroll.

Adicione o abaixo à sua subclasse do UIScrollView e substitua o TileContaiRerview pela visualização que contém sua imagem ou ladrilhos:

- (void)layoutSubviews {
    [super layoutSubviews];

    // center the image as it becomes smaller than the size of the screen
    CGSize boundsSize = self.bounds.size;
    CGRect frameToCenter = tileContainerView.frame;

    // center horizontally
    if (frameToCenter.size.width < boundsSize.width)
        frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
    else
        frameToCenter.origin.x = 0;

    // center vertically
    if (frameToCenter.size.height < boundsSize.height)
        frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
    else
        frameToCenter.origin.y = 0;

    tileContainerView.frame = frameToCenter;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top