UIScrollView mit zentriert UIImageView, wie Fotos App

stimmen
37

Ich möchte Scroll-Ansicht mit einem Bildseiten haben. Das Bild ist tatsächlich Karte, die viel größer als der Bildschirm ist. Die Karte sollte in der Mitte der Bildlaufansicht anfänglich, wie Fotos in Foto-App, wenn Sie das iPhone im Querformat drehen.

Alt-Text

Ich habe es nicht geschafft mit der richtigen Zoomen und Scrollen in der gleichen Zeit die Karte in der Mitte zu haben. Vorausgesetzt, dass das Kartenbild beginnt vom oberen Rand des Bildschirms (im Hochformat), sieht der Code so etwas wie:

- (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;
}

Wenn ich den Bildrahmen in die Mitte bewegen, wächst das Bild nur von der Spitze seines Rahmens nach unten. Ich habe versucht, mit mapView zu spielen, um transformieren, mit dem Rahmen des Imageview dynamisch zu verändern. Nichts funktioniert für mich so weit.

Veröffentlicht am 12/03/2009 um 12:56
quelle vom benutzer
In anderen Sprachen...                            


11 antworten

stimmen
40

Dieser Code soll auf den meisten Versionen von iOS arbeiten (und wurde auf 3.1 nach oben arbeiten getestet).

Es basiert auf dem Apple WWDC Code in Jonas Antwort erwähnt.

Fügen Sie die unten an der Unterklasse von UIScrollView, und ersetzt tileContainerView mit der Ansicht mit Ihrem Bild oder Fliesen:

- (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;
}
Beantwortet am 13/08/2010 um 17:42
quelle vom benutzer

stimmen
23

Hier ist, was ich als würde, die Lösung, wie in es genau wie die Foto-App Apfel verhält. Ich hatte Lösungen gewesen verwendet, die verwendet:

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

nicht wie diese Lösung rieren, aber ich habe da nach dem Zoomen getan wurde, ist es in die Mitte dann schnell ‚Sprung‘ abprallen würde, die sehr un-sexy war. Es stellte sich heraus, wenn man so ziemlich genau die gleiche Logik tun, aber in diesem Delegatfunktion:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

es beide beginnt zentriert und wenn Sie die Ansicht verkleinern es bleibt zentriert:

-(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;
}

Wo ‚Imageview‘ ist die UIImageViewSie verwenden.

Beantwortet am 03/02/2010 um 03:51
quelle vom benutzer

stimmen
7

Apple hat die 2010 WWDC Sitzung Videos zu allen Mitgliedern des iPhone Developer Programms freigegeben. Eines der Themen diskutiert wird, ist, wie sie die Fotos App erstellt !!! Sie bauen einen sehr ähnlichen App Schritt für Schritt und haben gemacht gesamten Code kostenlos zur Verfügung.

Dabei spielt es keine privaten api entweder verwenden. Ich kann nicht von dem Code setze hier wegen der Geheimhaltungsvereinbarung, aber hier ist ein Link zu dem Beispielcode herunterladen. Sie werden wahrscheinlich Zugang zu erhalten müssen sich anmelden.

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

Und ist, hier ein Link zum iTunes WWDC Seite:

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

Beantwortet am 20/06/2010 um 20:48
quelle vom benutzer

stimmen
2

Ich vermute , dass Sie die festlegen müssen UIScrollView‚s contentOffset.

Beantwortet am 12/03/2009 um 20:16
quelle vom benutzer

stimmen
1

Dieser arbeitete für mich:

- (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);

}

wo 160 ist die halbe Breite / Höhe Ihres UIScrollView.

Dann später habe ich die Content dem hier gefangen.

Beantwortet am 31/03/2009 um 09:15
quelle vom benutzer

stimmen
1

Ich wünschte, es wäre so einfach. Ich habe einige Nachforschungen im Netz und fand, dass es nicht nur mein Problem, aber viele Menschen mit dem gleichen Problem nicht nur auf dem iPhone zu kämpfen hat, aber auf Apples Desktop Cocoa auch. Siehe folgende Links:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
Die beschriebene Lösung auf dem Grundstück UIViewContentModeScaleAspectFit des Bildes basiert, aber leider funktioniert es nicht sehr gut .Das Bild ist zentriert und wächst richtig, scheint aber das Prellen Fläche viel größer zu sein als das Bild.

Dieser Kerl hat nicht die Antwort entweder:
http://discussions.apple.com/thread.jspa?messageID=8322675

Und schließlich das gleiche Problem auf Apples Desktop Cocoa:
http://www.cocoadev.com/index.pl?CenteringInsideNSScrollView
Ich nehme an, die Lösung funktioniert, aber es basiert auf dem NSClipView, die nicht auf dem iPhone ist ...

Jeder hat eine Lösung auf dem iPhone zu arbeiten?

Beantwortet am 13/03/2009 um 08:29
quelle vom benutzer

stimmen
0

Hier ist eine alternative Lösung, ähnlich wie @ JosephH Antwort, aber diese berücksichtigt die tatsächlichen Abmessungen des Bildes. So dass, wenn der Benutzer Pfannen / Zooms, die Sie nie mehr Leerzeichen haben auf dem Bildschirm als erforderlich. Dies ist ein häufiges Problem, zum Beispiel, wenn eine Landschaft Bild auf einem Porträt-Bildschirm zeigt. Es geht um Leerzeichen über und unter dem Bild sein, wenn das gesamte Bild auf dem Bildschirm ist (Aspect-Fit). Wenn dann ein-, betrachten die anderen Lösungen, die Leerzeichen als Teil des Bildes, weil es in der Imageview ist. Sie lassen Sie die Mehrheit des Bildes außerhalb des Bildschirms verschieben, nur die Leerzeichen sichtbar bleibt. Dies sieht schlecht aus für den Benutzer.

Mit dieser Klasse müssen Sie den Imageview passieren mit es funktioniert. Ich war versucht , um es automatisch erkennen, aber das ist schneller und Sie wollen , dass alle die Geschwindigkeit Sie im bekommen layoutSubviewsMethode.

Hinweis: Da ist, erfordert dies, dass Autolayout nicht für die Scrollview aktiviert ist.

//
//  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
    }
}
Beantwortet am 05/05/2016 um 09:56
quelle vom benutzer

stimmen
0

In Monotouch, die für mich gearbeitet.

this._scroll.ScrollRectToVisible(new RectangleF(_scroll.ContentSize.Width/2, _scroll.ContentSize.Height/2,1,1),false);
Beantwortet am 08/08/2012 um 15:45
quelle vom benutzer

stimmen
0

Eine elegante Möglichkeit , den Inhalt zu zentrieren , UISCrollViewist dies.

Fügen Sie einen Beobachter an den Content Ihrer UIScrollView, so wird diese Methode bei jedem Besuch der Inhaltsänderung aufgerufen werden ...

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

Jetzt auf Ihrer Beobachter-Methode:

- (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 ); }
  • Sie sollten das ändern [pointer viewWithTag:100]. Ersetzen Sie durch Ihre Inhalte Ansicht UIView.

    • Ändern Sie auch die imageGalleryauf Ihre Fenstergröße.

Dadurch wird das Zentrum des Inhalts jedes Mal seine Größe ändern korrigieren.

HINWEIS: Die einzige Möglichkeit , diese Inhalte nicht sehr gut funktionieren , ist mit Standard - Zoom - Funktionalität der UIScrollView.

Beantwortet am 03/11/2009 um 18:14
quelle vom benutzer

stimmen
0

Okay, ich glaube, ich habe eine ziemlich gute Lösung für dieses Problem gefunden. Der Trick besteht darin, ständig die Imageview-Rahmen neu einzustellen. Ich finde, das funktioniert viel besser, als ständig die contentInsets oder contentOffSets einzustellen. Ich hatte ein bisschen mehr Code hinzufügen beide Portrait- und Landschaftsbilder aufzunehmen.

Hier ist der Code:

- (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];
}
Beantwortet am 04/10/2009 um 03:16
quelle vom benutzer

stimmen
0

Hinweis: Diese Methode Art der Arbeiten. Wenn das Bild kleiner als die Imageview ist, wird es scrollen teilweise aus dem Bildschirm. Keine große Sache, aber auch nicht so schön wie die Fotos App.

Erstens ist es wichtig zu verstehen, dass wir mit zwei Ansichten zu tun hat, den Imageview mit dem Bild in ihm, und die Scrollview mit dem Imageview in ihm. Also, zuerst die Bildansicht auf die Größe des Bildschirms:

 [myImageView setFrame:self.view.frame];

Dann Zentrieren Sie Ihr Bild in der Imageview:

 myImageView.contentMode = UIViewContentModeCenter;

Hier ist meine gesamte Code:

- (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];
 }
Beantwortet am 08/09/2009 um 03:14
quelle vom benutzer

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