UIScrollView con UIImageView centrato, come app Foto

voti
37

Mi piacerebbe avere vista di scorrimento con una vista contenuto dell'immagine. L'immagine è in realtà mappa che è molto più grande rispetto allo schermo. La mappa dovrebbe essere inizialmente nel centro della vista di scorrimento, come foto in foto app quando si accende iPhone ad orientamento orizzontale.

alt

Non sono riuscito ad avere la mappa in centro con la corretta zoom e lo scorrimento allo stesso tempo. A condizione che l'immagine della mappa inizia dalla parte superiore dello schermo (in orientamento verticale), il codice simile a:

- (void)loadView {
    mapView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@map.jpg]];
    CGFloat mapHeight = MAP_HEIGHT * SCREEN_WIDTH / MAP_WIDTH;
    mapView.frame = CGRectMake(0, 0, SCREEN_WIDTH, mapHeight);
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    scrollView.delegate = self;
    scrollView.contentSize = mapView.frame.size;
    scrollView.maximumZoomScale = MAP_WIDTH / SCREEN_WIDTH;
    scrollView.minimumZoomScale = 1;
    [scrollView addSubview:mapView];
    self.view = scrollView;
}

Quando sposto il frame di immagine al centro, l'immagine cresce solo dalla parte superiore del suo telaio giù. Ho provato a giocare con MapView trasformare, con il cambiamento dinamico cornice del ImageView. Nulla funziona per me finora.

È pubblicato 12/03/2009 alle 12:56
fonte dall'utente
In altre lingue...                            


11 risposte

voti
40

Questo codice dovrebbe funzionare sulla maggior parte delle versioni di iOS (ed è stato testato per funzionare su 3.1 verso l'alto).

E 'basato sul codice di Apple WWDC menzionato nella risposta di Giona.

Aggiungere il seguente per la vostra sottoclasse di UIScrollView, e sostituire tileContainerView con la vista contenente l'immagine o piastrelle:

- (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;
}
Risposto il 13/08/2010 a 17:42
fonte dall'utente

voti
23

Ecco quello che avevo in considerazione, la soluzione come in esso si comporta esattamente come la foto app di Apple. Ero stato con soluzioni che hanno utilizzato:

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

per centrare nuovamente, ma non mi piaceva questa soluzione perché dopo lo zoom è stato fatto, che sarebbe poi rimbalzare veloce 'salto' verso il centro, che era molto poco sexy. Si scopre che se praticamente fare la stessa identica logica, ma in questa funzione delegato:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

esso sia inizia centrato e quando si esegue lo zoom out che rimane centrato:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView {
CGRect innerFrame = imageView.frame;
CGRect scrollerBounds = pScrollView.bounds;

if ( ( innerFrame.size.width < scrollerBounds.size.width ) || ( innerFrame.size.height < scrollerBounds.size.height ) )
{
    CGFloat tempx = imageView.center.x - ( scrollerBounds.size.width / 2 );
    CGFloat tempy = imageView.center.y - ( scrollerBounds.size.height / 2 );
    CGPoint myScrollViewOffset = CGPointMake( tempx, tempy);

    pScrollView.contentOffset = myScrollViewOffset;

}

UIEdgeInsets anEdgeInset = { 0, 0, 0, 0};
if ( scrollerBounds.size.width > innerFrame.size.width )
{
    anEdgeInset.left = (scrollerBounds.size.width - innerFrame.size.width) / 2;
    anEdgeInset.right = -anEdgeInset.left;  // I don't know why this needs to be negative, but that's what works
}
if ( scrollerBounds.size.height > innerFrame.size.height )
{
    anEdgeInset.top = (scrollerBounds.size.height - innerFrame.size.height) / 2;
    anEdgeInset.bottom = -anEdgeInset.top;  // I don't know why this needs to be negative, but that's what works
}
pScrollView.contentInset = anEdgeInset;
}

Dove 'ImageView' è la UIImageViewsi sta utilizzando.

Risposto il 03/02/2010 a 03:51
fonte dall'utente

voti
7

Apple ha rilasciato il video di sessione WWDC 2010 a tutti i membri del iPhone Developer Program. Uno dei temi discussi è come hanno creato la foto app !!! Costruiscono un passo applicazione molto simile passo e hanno fatto tutto il codice disponibile gratuitamente.

Non usa api privato sia. Non posso mettere qualsiasi codice qui a causa dell'accordo di non divulgazione, ma qui è un link al codice di esempio download. Sarà probabilmente necessario eseguire il login per ottenere l'accesso.

http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645

E, ecco un link alla pagina di iTunes WWDC:

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

Risposto il 20/06/2010 a 20:48
fonte dall'utente

voti
2

Ho il sospetto che è necessario impostare la UIScrollView's contentOffset.

Risposto il 12/03/2009 a 20:16
fonte dall'utente

voti
1

Questo ha funzionato per me:

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
CGFloat tempx = view.center.x-160;
CGFloat tempy = view.center.y-160;
myScrollViewOffset = CGPointMake(tempx,tempy);

}

dove 160 è la metà della larghezza / altezza del vostro UIScrollView.

Poi più tardi ho impostato il contentOffset a quello catturato qui.

Risposto il 31/03/2009 a 09:15
fonte dall'utente

voti
1

Mi piacerebbe che fosse così semplice. Ho fatto qualche ricerca su internet e ha scoperto che non è solo un problema mio, ma molte persone sono alle prese con lo stesso problema, non solo su iPhone, ma il cacao del desktop di Apple pure. Vedere seguenti link:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
La soluzione descritta si basa sulla proprietà UIViewContentModeScaleAspectFit dell'immagine, ma purtroppo non funziona molto bene L'immagine viene centrato e cresce correttamente, ma l'area che rimbalza sembra essere molto più grande di quanto l'immagine.

Questo ragazzo non ha ottenuto la risposta sia:
http://discussions.apple.com/thread.jspa?messageID=8322675

E, infine, lo stesso problema su cacao del desktop di Apple:
http://www.cocoadev.com/index.pl?CenteringInsideNSScrollView
Suppongo che la soluzione funziona, ma si basa sul NSClipView, che non è su iPhone ...

Qualcuno ha qualche soluzione di lavoro su iPhone?

Risposto il 13/03/2009 a 08:29
fonte dall'utente

voti
0

Ecco una soluzione alternativa, simile a @ risposta di JosephH, ma questo tiene conto delle reali dimensioni dell'immagine. In modo che quando le padelle utente / zoom, non hai mai hanno più spazio bianco sullo schermo di quanto richiesto. Questo è un problema comune, ad esempio quando mostra un paesaggio immagine su uno schermo verticale. Ci sara 'spazio bianco sopra e sotto l'immagine quando l'intera immagine è sullo schermo (Aspect Fit). Poi, quando lo zoom, le altre soluzioni ritengono che gli spazi bianchi come parte dell'immagine, perché è nel ImageView. Essi vi permetterà di eseguire una panoramica la maggior parte delle immagini fuori dallo schermo, lasciando solo il visibile spazi bianchi. Questo sembra male per l'utente.

Con questa classe, si ha bisogno di passare l'ImageView che sta funzionando con. Ero tentato di farlo rilevare automaticamente, ma questo è più veloce e si desidera che tutta la velocità si può ottenere nel layoutSubviewsmetodo.

Nota: Come è, questo richiede che AutoLayout non è abilitato per la ScrollView.

//
//  CentringScrollView.swift
//  Cerebral Gardens
//
//  Created by Dave Wood
//  Copyright © 2016 Cerebral Gardens Inc. All rights reserved.
//

import UIKit

class CentringScrollView: UIScrollView {

    var imageView: UIImageView?

    override func layoutSubviews() {
        super.layoutSubviews()

        guard let superview = superview else { return }
        guard let imageView = imageView else { return }
        guard let image = imageView.image else { return }

        var frameToCentre = imageView.frame

        let imageWidth = image.size.width
        let imageHeight = image.size.height

        let widthRatio = superview.bounds.size.width / imageWidth
        let heightRatio = superview.bounds.size.height / imageHeight

        let minRatio = min(widthRatio, heightRatio, 1.0)

        let effectiveImageWidth = minRatio * imageWidth * zoomScale
        let effectiveImageHeight = minRatio * imageHeight * zoomScale

        contentSize = CGSize(width: max(effectiveImageWidth, bounds.size.width), height: max(effectiveImageHeight, bounds.size.height))

        frameToCentre.origin.x = (contentSize.width - frameToCentre.size.width) / 2
        frameToCentre.origin.y = (contentSize.height - frameToCentre.size.height) / 2

        imageView.frame = frameToCentre
    }
}
Risposto il 05/05/2016 a 09:56
fonte dall'utente

voti
0

In MonoTouch che ha lavorato per me.

this._scroll.ScrollRectToVisible(new RectangleF(_scroll.ContentSize.Width/2, _scroll.ContentSize.Height/2,1,1),false);
Risposto il 08/08/2012 a 15:45
fonte dall'utente

voti
0

Un modo elegante per centrare il contenuto UISCrollViewè questo.

Aggiungere un osservatore alla contentSize del vostro UIScrollView, quindi questo metodo sarà chiamato ogni volta che il cambiamento dei contenuti ...

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

Ora sul vostro metodo di osservatore:

- (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 ); }
  • Si dovrebbe cambiare il [pointer viewWithTag:100]. Sostituire con la visualizzazione dei contenuti UIView.

    • Anche cambiare imageGalleryindicando le dimensioni della finestra.

Ciò correggerà il centro del everytime contenuti sua cambio formato.

NOTA: L'unico modo questo contenuto non funziona molto bene è con funzionalità zoom standard del UIScrollView.

Risposto il 03/11/2009 a 18:14
fonte dall'utente

voti
0

Va bene, penso di aver trovato un buon soluzione a questo problema. Il trucco è quello di regolare costantemente telaio della ImageView. Trovo che questo funziona molto meglio di regolare costantemente i contentInsets o contentOffSets. Ho dovuto aggiungere un po 'di codice aggiuntivo per accogliere entrambe le immagini verticale e orizzontale.

Ecco il codice:

- (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];
}
Risposto il 04/10/2009 a 03:16
fonte dall'utente

voti
0

Nota: questo metodo tipo di opere. se l'immagine è più piccola IMAGEVIEW, sarà scorrere parzialmente fuori dallo schermo. Non è un grosso problema, ma anche non bello come le foto app.

In primo luogo, è importante capire che abbiamo a che fare con 2 viste, l'imageview con l'immagine in esso, e la ScrollView con l'ImageView in esso. Quindi, prima impostare l'ImageView alle dimensioni dello schermo:

 [myImageView setFrame:self.view.frame];

Poi, centrare l'immagine nel ImageView:

 myImageView.contentMode = UIViewContentModeCenter;

Ecco tutto il mio codice:

- (void)viewDidLoad {
AppDelegate *appDelegate = (pAppDelegate *)[[UIApplication sharedApplication] delegate];
 [super viewDidLoad];
 NSString *Path = [[NSBundle mainBundle] bundlePath];
 NSString *ImagePath = [Path stringByAppendingPathComponent:(@"data: %@", appDelegate.MainImageName)];
 UIImage *tempImg = [[UIImage alloc] initWithContentsOfFile:ImagePath];
 [imgView setImage:tempImg];

 myScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
 [myScrollView addSubview:myImageView];

//Set ScrollView Appearance
 [myScrollView setBackgroundColor:[UIColor blackColor]];
 myScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;

//Set Scrolling Prefs
 myScrollView.bounces = YES;
 myScrollView.delegate = self;
 myScrollView.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
 [myScrollView setCanCancelContentTouches:NO];
 [myScrollView setScrollEnabled:YES];


//Set Zooming Prefs
 myScrollView.maximumZoomScale = 3.0;
 myScrollView.minimumZoomScale = CGImageGetWidth(tempImg.CGImage)/320;
 myScrollView.zoomScale = 1.01; //Added the .01 to enable scrolling immediately upon view load.
 myScrollView.bouncesZoom = YES;


 [myImageView setFrame:self.view.frame];//rect];// .frame.size.height = imageHeight;
 myImageView.contentMode = UIViewContentModeCenter;
 self.view = myScrollView;
 [tempImg release];
 }
Risposto il 08/09/2009 a 03:14
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more