UIScrollView z UIImageView wyśrodkowany, jak aplikacji Zdjęcia

głosy
37

Chciałbym mieć przewijania widoku z widoku zawartości obrazu. Obraz jest faktycznie mapa, która jest znacznie większa niż na ekranie. Mapa powinna być początkowo w centrum widoku przewijania, jak zdjęcia w aplikacji Zdjęcia po włączeniu iPhone do orientacji poziomej.

tekst

Nie udało mi się mieć mapę w środku z prawidłowym powiększania i przewijania w tym samym czasie. Pod warunkiem, że obraz mapy rozpoczyna się od górnej części ekranu (w orientacji pionowej), kod wygląda mniej więcej tak:

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

Kiedy przesunąć ramkę obrazu do środka, obraz rośnie tylko z wierzchu swojej ramie w dół. Starałem się bawić z MapView przekształcać, z dynamicznie zmieniających klatkę ImageView. Nic nie działa na mnie tak daleko.

Utwórz 12/03/2009 o 12:56
źródło użytkownik
W innych językach...                            


11 odpowiedzi

głosy
40

Kod ten powinien działać na większości wersji iOS (i został przetestowany do pracy na 3,1 w górę).

Jest on oparty na kodzie firmy Apple WWDC wspomniano w odpowiedzi Jonasza.

Dodaj poniżej do podklasy UIScrollView i zastąpić tileContainerView z widoku zawierającego zdjęcie lub płytek:

- (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;
}
Odpowiedział 13/08/2010 o 17:42
źródło użytkownik

głosy
23

Oto co Pomyślę, rozwiązanie jak w to zachowuje się dokładnie jak Apple zdjęciem aplikacji. Byłem przy użyciu rozwiązań, które stosowane:

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

aby pojawiło, ale nie lubiłem tego rozwiązania, ponieważ po powiększanie się stało, że to odbić następnie szybki „skok” do centrum, co było bardzo un-sexy. Okazuje się, jeśli dość dużo zrobić dokładnie taką samą logikę, ale w tej funkcji delegata:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

to zarówno zaczyna się na środku i po pomniejszyć to pozostaje wyśrodkowany:

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

Gdzie ImageView "jest UIImageViewużywasz.

Odpowiedział 03/02/2010 o 03:51
źródło użytkownik

głosy
7

Firma Apple opublikowała wideo sesji WWDC 2010 wszystkim członkom programu iPhone Developer. Jednym z tematów omawianych sposób stworzyli aplikację Zdjęcia !!! Budują bardzo podobną aplikację krok po kroku i dokonały cały kod dostępny za darmo.

Nie używa prywatnego API albo. Nie mogę umieścić dowolny kodu tutaj ze względu na umowy o zakazie ujawniania, ale tu jest link do pobrania przykładowy kod. Prawdopodobnie będziesz musiał się zalogować, aby uzyskać dostęp.

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

A tu jest link do strony 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

Odpowiedział 20/06/2010 o 20:48
źródło użytkownik

głosy
2

Podejrzewam, że trzeba ustawić UIScrollView„s contentOffset.

Odpowiedział 12/03/2009 o 20:16
źródło użytkownik

głosy
1

Ten pracował dla mnie:

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

}

gdzie 160 to połowa szerokość / wysokość twoich UIScrollView.

Potem ustawić contentoffset do jednego zdobytego tutaj.

Odpowiedział 31/03/2009 o 09:15
źródło użytkownik

głosy
1

Chciałbym, żeby to było takie proste. Zrobiłem rozeznanie w internecie i okazało się, że to nie jest tylko mój problem, ale wiele osób boryka się z tym samym numerze nie tylko na iPhone, ale na pulpicie Apple kakao, jak również. Zobacz poniższe linki:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
Opisane rozwiązanie jest oparte na UIViewContentModeScaleAspectFit własności obrazu, ale niestety to nie działa bardzo dobrze .Powierzchnia zdjęcie centered i rośnie prawidłowo, ale obszar odbijając wydaje się być znacznie większy niż na zdjęciu.

Ten facet nie uzyskać odpowiedź albo:
http://discussions.apple.com/thread.jspa?messageID=8322675

I wreszcie, ten sam problem na pulpicie Apple kakao:
http://www.cocoadev.com/index.pl?CenteringInsideNSScrollView
Przypuszczam, że rozwiązanie działa, ale jest ona oparta na NSClipView, który nie jest na iPhone ...

Ktoś ma jakieś rozwiązanie pracuje na iPhone?

Odpowiedział 13/03/2009 o 08:29
źródło użytkownik

głosy
0

Oto alternatywnym rozwiązaniem, podobnie jak @ odpowiedź JosephH, ale ten uwzględnia rzeczywiste wymiary obrazu. Tak, że gdy użytkownik / patelnie zoomy, nie musisz więcej spacji na ekranie niż wymagane. Jest to częsty problem na przykład podczas wyświetlania obrazu krajobraz na ekranie pionowym. Nie będzie spacje powyżej i poniżej obrazu, gdy cały obraz jest na ekranie (Aspect Fit). Potem, gdy powiększanie, inne rozwiązania uważają, że spacje jako część obrazu, bo to w ImageView. Będą one pozwalają przesuwać większość obrazem poza ekranem, pozostawiając tylko białe znaki widoczne. To wygląda źle dla użytkownika.

Z tej klasy, trzeba zrobić, aby przekazać mu ImageView to pracujesz. Kusiło mnie, aby mieć to auto wykryć, ale jest szybszy i chcesz wszystko prędkość można uzyskać w layoutSubviewsmetodzie.

Uwaga: Ponieważ jest to wymaga autoLayout nie jest włączona dla 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
    }
}
Odpowiedział 05/05/2016 o 09:56
źródło użytkownik

głosy
0

W MonoTouch że pracował dla mnie.

this._scroll.ScrollRectToVisible(new RectangleF(_scroll.ContentSize.Width/2, _scroll.ContentSize.Height/2,1,1),false);
Odpowiedział 08/08/2012 o 15:45
źródło użytkownik

głosy
0

Jeden elegancki sposób, aby wyśrodkować zawartość UISCrollViewjest następująca.

Dodaj jednego obserwatora do contentSize twoich UIScrollView, więc ta metoda będzie wywoływana za każdym razem zawartość zmiana ...

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

Teraz od metody obserwacyjnej:

- (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 ); }
  • Należy zmienić [pointer viewWithTag:100]. Zastąpić widoku zawartości UIView.

    • Zmienić również imageGalleryskierowaną do wielkości okna.

Pozwoli to poprawić środek zawartość za każdym razem jego zmiany rozmiaru.

UWAGA: Jedynym sposobem ta treść nie działa bardzo dobrze jest ze standardową funkcjonalność zoomu UIScrollView.

Odpowiedział 03/11/2009 o 18:14
źródło użytkownik

głosy
0

Okay, myślę, że znalazłem całkiem dobre rozwiązanie tego problemu. Sztuką jest stale wyregulować ramka ImageView użytkownika. Uważam to działa znacznie lepiej niż stale dostosowując contentInsets lub contentOffSets. Musiałem dodać trochę więcej kodu, aby pomieścić zarówno obrazy portretowe i krajobrazowe.

Oto kod:

- (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];
}
Odpowiedział 04/10/2009 o 03:16
źródło użytkownik

głosy
0

Uwaga: Ta metoda rodzaju prac. jeśli obraz jest mniejszy niż ImageView będzie przewijać częściowo na ekranie. Nic wielkiego, ale też nie tak ładne jak na zdjęciach aplikacji.

Po pierwsze, ważne jest, aby zrozumieć, że mamy do czynienia z 2 widoki, ImageView z obrazem w nim, a Scrollview z ImageView w nim. Więc najpierw ustawić ImageView do rozmiaru ekranu:

 [myImageView setFrame:self.view.frame];

Następnie wyśrodkować obraz na ImageView:

 myImageView.contentMode = UIViewContentModeCenter;

Oto mój cały kod:

- (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];
 }
Odpowiedział 08/09/2009 o 03:14
źródło użytkownik

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