UIScrollView se soustředil UIImageView, jako jsou fotografie app

hlasů
37

Chtěl bych mít navigační pohled s výhledem k obsahu obrazu. Obraz je vlastně mapa, která je mnohem větší než na obrazovce. Mapa by měla být zpočátku ve středu pohledu scroll, jako jsou fotografie v aplikaci Fotografie, když zapnete iPhone na šířku.

alt

Mi nepodařilo mít mapu v centru se správným zvětšení a rolování ve stejnou dobu. Za předpokladu, že mapa image začíná od horní části obrazovky (na výšku), kód vypadá nějak takto:

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

Když jsem se přesunout rám obrazu do středu, obraz roste pouze z horní části rámu dolů. Snažil jsem se hrát si s MapView transformace, s dynamicky se měnící snímek imageView. Nic nefunguje pro mě tak daleko.

Položena 12/03/2009 v 12:56
zdroj uživatelem
V jiných jazycích...                            


11 odpovědí

hlasů
40

Tento kód by měl fungovat na většině verzí iOS (a byl testován pracovat na 3,1 směrem nahoru).

Je založen na kódu Apple WWDC uvedené v Jonaha odpovědi.

Přidejte níže vaší podtřídy UIScrollView a nahradit tileContainerView s názorem, který obsahuje disk nebo dlaždice:

- (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;
}
Odpovězeno 13/08/2010 v 17:42
zdroj uživatelem

hlasů
23

Zde je to, co bych zvážit řešení, jak v ní chová přesně jako foto app Apple. Byl jsem za použití roztoků, které byly dříve:

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

na recenter ale neudělal jsem to jako ta řešení, protože po přiblížení se stalo, bylo by to odrazí poté rychle ‚skok‘ do středu, který byl velmi un-sexy. Ukázalo se, že pokud se do značné míry dělat přesně stejné logiky, ale v této funkci delegáta:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

že oba začíná soustředěný a když se vzdálíte, že zůstane na střed:

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

Kde imageView "je UIImageViewpoužíváte.

Odpovězeno 03/02/2010 v 03:51
zdroj uživatelem

hlasů
7

Apple vydal WWDC relace videa v roce 2010 pro všechny členy programu iPhone vývojáře. Jedním z diskutovaných témat je, jak oni vytvořili fotografie aplikaci !!! Stavějí velmi podobnou aplikaci krok za krokem, a dělali celý kód k dispozici zdarma.

Nepoužívá soukromé api jeden. Nemohu dát jakýkoliv kódu tady, protože dohody o nezveřejnění, ale tady je odkaz na ukázkový kód ke stažení. Pravděpodobně budete muset přihlásit, aby získali přístup.

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

A zde je odkaz na stránku 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

Odpovězeno 20/06/2010 v 20:48
zdroj uživatelem

hlasů
2

Domnívám se, že je třeba nastavit UIScrollView‚s contentOffset.

Odpovězeno 12/03/2009 v 20:16
zdroj uživatelem

hlasů
1

Tato pracoval pro mě:

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

}

kde 160 je polovina šířka / výška vašich UIScrollView.

Později jsem nastavit contentoffset k jednomu zde zachycen.

Odpovězeno 31/03/2009 v 09:15
zdroj uživatelem

hlasů
1

Kéž by to bylo tak jednoduché. Udělal jsem nějaký výzkum na internetu a zjistil, že to není jen můj problém, ale mnoho lidí se potýkají se stejným problematice nejen na iPhone, ale na Apple stolním Cocoa stejně. Viz následující odkazy:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
Popsané řešení je založeno na pozemku UIViewContentModeScaleAspectFit obrazu, ale bohužel to nefunguje dobře .v obrázek soustředěný a roste dobře, ale skákací plocha se zdá být mnohem větší, než na obrázku.

Ten chlap nedostal odpověď buď:
http://discussions.apple.com/thread.jspa?messageID=8322675

A konečně, stejný problém na Apple stolním kakao:
http://www.cocoadev.com/index.pl?CenteringInsideNSScrollView
Myslím, že řešení funguje, ale je založen na NSClipView, který není na iPhone ...

Každý, kdo má nějaké řešení pracuje na iPhone?

Odpovězeno 13/03/2009 v 08:29
zdroj uživatelem

hlasů
0

Zde je alternativní řešení, podobně jako @ JosephH odpověď, ale to se vezme v úvahu skutečné rozměry obrazu. Takže když uživatel pánve / zoomy nikdy máte větší mezery na obrazovce, než je vyžadováno. Jedná se o běžný problém, například při zobrazení na šířku obrazu na obrazovce na výšku. Tam to bude mezery nad a pod obrazem, kdy celý obrázek na obrazovce (Aspect Fit). Pak, když přiblížení se jiná řešení se domnívají, že mezery jako součást obrazu, protože je to v imageView. Oni vám umožní posunout většinu obrazu mimo obrazovku, takže jen prázdné místo viditelné. Vypadá to špatné pro uživatele.

Díky této třídě, ale musíte projít jí imageView to pracujete. Byl jsem v pokušení, aby to automaticky detekovat, ale je to rychlejší a chcete všechnu rychlost, kterou lze získat v layoutSubviewsmetodě.

Poznámka: Jak je to vyžaduje, aby Automatický návrh není povoleno pro 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
    }
}
Odpovězeno 05/05/2016 v 09:56
zdroj uživatelem

hlasů
0

V MonoTouch která pracovala pro mě.

this._scroll.ScrollRectToVisible(new RectangleF(_scroll.ContentSize.Width/2, _scroll.ContentSize.Height/2,1,1),false);
Odpovězeno 08/08/2012 v 15:45
zdroj uživatelem

hlasů
0

Jeden elegantní způsob, jak do centra obsah UISCrollViewje tento.

Přidat jednoho pozorovatele na contentSize vašeho UIScrollView, takže tato metoda bude volána pokaždé obsah změna ...

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

Nyní na metodě pozorovatele:

- (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 ); }
  • Měli byste změnit [pointer viewWithTag:100]. Nahradit svůj obsah pohledu UIView.

    • Také změnit imageGalleryukázal na velikost okna.

To opraví střed pokaždé obsahu jeho změny velikosti.

POZNÁMKA: Jediným způsobem, jak tento obsah nejsou funguje velmi dobře, je standardní funkcí přiblížení UIScrollView.

Odpovězeno 03/11/2009 v 18:14
zdroj uživatelem

hlasů
0

Dobře, myslím, že jsem našel docela dobré řešení tohoto problému. Trik je v tom stále znovu nastavit rámeček na imageView je. Připadá mi to funguje mnohem lépe, než neustále nastavením contentInsets nebo contentOffSets. Musel jsem se přidat trochu kódu navíc přizpůsobit výšku i na šířku obrazu.

Zde je kód:

- (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];
}
Odpovězeno 04/10/2009 v 03:16
zdroj uživatelem

hlasů
0

Poznámka: Tato metoda druh prací. pokud je obrázek menší než imageView bude posouvat částečně mimo obrazovku. Není velký problém, ale ne tak hezky jako fotografie app.

Za prvé, je důležité pochopit, že máme co do činění s 2 pohledy, na imageview s obrazem v něm, a scrollview s imageview v něm. Takže, nejprve nastavit imageview na velikost obrazovky:

 [myImageView setFrame:self.view.frame];

Poté střed disk v imageview:

 myImageView.contentMode = UIViewContentModeCenter;

Zde je celý můj kód:

- (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];
 }
Odpovězeno 08/09/2009 v 03:14
zdroj uživatelem

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