UIScrollView met gecentreerde UIImageView, zoals foto's app

stemmen
37

Ik wil graag scroll weergave met een beeldinhoud uitzicht. Het beeld is eigenlijk kaart die veel groter is dan het scherm. De kaart moet in eerste instantie in het midden van de scroll view, zoals foto's in foto's app als je iPhone te zetten naar de liggende stand.

Alt-tekst

Ik slaagde er niet in om de kaart in het centrum met de juiste zoomen en scrollen op hetzelfde moment te hebben. Met dien verstande dat het de kaart begint vanaf de bovenkant van het scherm (in staand), de code ziet er ongeveer zo:

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

Toen ik naar het centrum van het beeld te bewegen frame, de afbeelding groeit alleen vanaf de bovenkant van het frame naar beneden. Ik heb geprobeerd om te spelen met mapView transformeren, met dynamisch veranderende frame van de imageView. Niets werkt voor mij tot nu toe.

De vraag is gesteld op 12/03/2009 om 12:56
bron van user
In andere talen...                            


11 antwoorden

stemmen
40

Deze code zou moeten werken op de meeste versies van iOS (en is getest om te werken aan 3,1 naar boven).

Het is gebaseerd op het in het antwoord Jonah vermeld Apple WWDC code.

Voeg de hieronder om uw subklasse van UIScrollView, en vervang tileContainerView met de opvatting die uw afbeelding bevat of tegels:

- (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;
}
antwoordde op 13/08/2010 om 17:42
bron van user

stemmen
23

Hier is wat ik zou overwegen, de oplossing als in het precies gedraagt ​​als Apple's foto app. Ik was met behulp van oplossingen die gebruikt:

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

te kadreren, maar ik vond het niet leuk dat de oplossing, want na de zoomfunctie werd gedaan, zou het dan stuiteren quick 'springen' naar het centrum die zeer on-sexy was. Blijkt dat als je vrij veel doen precies dezelfde logica, maar in dit delegeren functie:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

het zowel begint gecentreerd en wanneer je uitzoomt hij blijft gecentreerd:

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

Waar imageView 'is het UIImageViewdie u gebruikt.

antwoordde op 03/02/2010 om 03:51
bron van user

stemmen
7

Apple heeft de 2010 WWDC sessie video vrijgegeven aan alle leden van de iPhone Developer Program. Een van de besproken onderwerpen is hoe ze gemaakt van de foto's app !!! Ze bouwen een zeer vergelijkbare app stap voor stap en hebben alle code gratis beschikbaar gesteld.

Het maakt niet gebruik maken van privé-api. Ik kan niet zetten van de code hier vanwege de non disclosure agreement, maar hier is een link naar het monster code download. U zult waarschijnlijk moet inloggen om toegang te krijgen.

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

En, hier is een link naar de iTunes WWDC pagina:

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

antwoordde op 20/06/2010 om 20:48
bron van user

stemmen
2

Ik vermoed dat je nodig hebt om de ingestelde UIScrollView's contentOffset.

antwoordde op 12/03/2009 om 20:16
bron van user

stemmen
1

Dit werkte voor mij:

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

}

waarbij 160 de helft van de breedte / hoogte van UIScrollView.

Later zette ik de contentoffset aan de ene gevangen hier.

antwoordde op 31/03/2009 om 09:15
bron van user

stemmen
1

Was het maar zo eenvoudig. Ik deed wat onderzoek op het net en vond dat het niet alleen mijn probleem, maar veel mensen worstelen met hetzelfde probleem niet alleen op de iPhone, maar Apple's desktop Cocoa ook. Zie onderstaande links:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
De beschreven oplossing is gebaseerd op het terrein UIViewContentModeScaleAspectFit van het beeld, maar helaas niet zo goed .De afbeelding is te werken gecentreerd en groeit goed, maar de stuiterende gebied lijkt te zijn veel groter dan de foto.

Deze man heeft het antwoord niet krijgen, hetzij:
http://discussions.apple.com/thread.jspa?messageID=8322675

En tot slot, het zelfde probleem op Apple's desktop Cocoa:
http://www.cocoadev.com/index.pl?CenteringInsideNSScrollView
Ik veronderstel dat de oplossing werkt, maar het is gebaseerd op de NSClipView, die niet op de iPhone ...

Iedereen heeft een aantal oplossing te werken op de iPhone?

antwoordde op 13/03/2009 om 08:29
bron van user

stemmen
0

Hier is een alternatieve oplossing, gelijk aan @ antwoord JosephH, maar dit houdt rekening met de werkelijke afmetingen van de afbeelding. Zodat wanneer de gebruiker pannen / zooms, u nooit meer witruimte op het scherm dan vereist. Dit is een veelvoorkomend probleem bijvoorbeeld wanneer een landschap beeld op een portret scherm tonen. Er gaat witruimte boven en onder het beeld wanneer het volledige beeld op het scherm (Aspect fit). Dan, bij het inzoomen, de andere oplossingen bedenkt dat witruimte als onderdeel van het beeld, omdat het in de imageView. Ze laten u de meerderheid van de afbeelding pan buiten het scherm, waardoor alleen de witruimte zichtbaar. Dit ziet er slecht uit voor de gebruiker.

Met deze klasse, heb je nodig om het te passeren de imageView het werkt met. Ik kwam in de verleiding om het te hebben automatisch te detecteren, maar dit is sneller en je wilt dat alle de snelheid die u kunt krijgen in de layoutSubviewsmethode.

Let op: Zoals, dit vereist dat AutoLayout niet is ingeschakeld voor de 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
    }
}
antwoordde op 05/05/2016 om 09:56
bron van user

stemmen
0

In MonoTouch die werkte voor mij.

this._scroll.ScrollRectToVisible(new RectangleF(_scroll.ContentSize.Width/2, _scroll.ContentSize.Height/2,1,1),false);
antwoordde op 08/08/2012 om 15:45
bron van user

stemmen
0

Een elegante manier om de inhoud van centreren UISCrollViewis dit.

Voeg een waarnemer bij de contentSize van je UIScrollView, dus deze methode zal iedere keer de inhoud verandering worden genoemd ...

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

Nu op uw waarnemer 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 ); }
  • Je moet het veranderen [pointer viewWithTag:100]. Vervangen door uw inhoud te bekijken UIView.

    • Verander ook imageGallerydie naar uw venster grootte.

Dit zal het centrum van de inhoud elke keer zijn grootte verandering te corrigeren.

LET OP: De enige manier waarop deze inhoud niet erg goed werkt niet met standaard zoom-functionaliteit van de UIScrollView.

antwoordde op 03/11/2009 om 18:14
bron van user

stemmen
0

Oké, ik denk dat ik een vrij goede oplossing voor dit probleem gevonden. De truc is om voortdurend bijstellen het frame van de imageView's. Ik vind dit veel beter werkt dan voortdurend aanpassen van de contentInsets of contentOffSets. Ik moest een beetje extra code toe te voegen aan zowel portret en landschap beelden tegemoet te komen.

Hier is de 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];
}
antwoordde op 04/10/2009 om 03:16
bron van user

stemmen
0

Let op: deze methode soort van werken. Als de afbeelding kleiner is dan het imageView, wordt deze gedeeltelijk over het scherm rollen. Geen big deal, maar ook niet zo mooi als de foto's app.

Ten eerste is het belangrijk om te begrijpen dat we te maken hebben met 2 uitzicht, de ImageView met het beeld in, en de ScrollView met de ImageView erin. Dus, eerst de ImageView om de grootte van het scherm:

 [myImageView setFrame:self.view.frame];

Dan, het centrum van uw beeld in het ImageView:

 myImageView.contentMode = UIViewContentModeCenter;

Hier is mijn volledige 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];
 }
antwoordde op 08/09/2009 om 03:14
bron van user

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