IPhone - полноэкранный режим UIScrollView запускается правильно, но перемещается под панель навигации - PullRequest
5 голосов
/ 15 сентября 2010

В настоящее время я пытаюсь реализовать средство выбора фотографий точно так же, как приложение Photo, но с пользовательским источником изображений.Для «прокрутки фотографий» я использовал пример кода Apple PhotoScroller и адаптировал его.Одним из основных отличий является то, что теперь он встроен в контроллер навигации (который является собственным навигационным контроллером photoPicker, а не в приложение) с панелью навигации.У меня есть статус и панель навигации полупрозрачные, и я установил wantFullScreenLayout = YES на всех контроллерах представления, используемых в PhotoPicker.Кажется, работает почти нормально.Представление «Обзор» (отображающее миниатюры всех фотографий альбома) действительно является полноэкранным, и мне нужно сместить его вручную, чтобы сначала миниатюры отображались под панелью навигации.Для прокрутки часть, однако, есть глюк.Для тех, кто не знает пример кода photoScroller, он работает с пользовательским UIViewController (PhotoViewController) с атрибутом UIScrollView (pagingScrollView) и набором пользовательских UIScrollView (ImageScrollView) с UIView и атрибутами индекса NSInteger.Затем экземпляры ImageScrollView добавляются / удаляются как подпредставления PhotoScroller.

Ниже приведен некоторый связанный код:

PhotoViewController.h

@interface PhotoViewController : UIViewController <UIScrollViewDelegate> {
    UIScrollView *pagingScrollView;

    NSMutableSet *recycledPages;
    NSMutableSet *visiblePages;

    IBOutlet UIToolbar *toolbar;
    IBOutlet UIBarButtonItem *previousButtonItem;
    IBOutlet UIBarButtonItem *nextButtonItem;

    id<PhotoViewDataSource> dataSource;
}

@property(nonatomic, retain) UIScrollView *pagingScrollView;
@property(nonatomic, retain) NSMutableSet *recylcledPages;
@property(nonatomic, retain) NSMutableSet *visiblePages;

@property(nonatomic, retain) UIToolbar *toolbar;
@property(nonatomic, retain) UIBarButtonItem *previousButtonItem;
@property(nonatomic, retain) UIBarButtonItem *nextButtonItem;

@property(nonatomic, retain) id<PhotoViewDataSource> dataSource;

PhotoViewController.m

- (void)loadView 
{
    self.wantsFullScreenLayout = YES;

    // Configure the scrollView
    CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
    pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
    pagingScrollView.pagingEnabled = YES;
    pagingScrollView.backgroundColor = [UIColor redColor];
    pagingScrollView.showsVerticalScrollIndicator = NO;
    pagingScrollView.showsHorizontalScrollIndicator = NO;
    pagingScrollView.contentSize = CGSizeMake(pagingScrollViewFrame.size.width * [self.dataSource imageCount],
                                              pagingScrollViewFrame.size.height);
    //pagingScrollView.contentOffset = CGPointMake(0, 0);

    pagingScrollView.delegate = self;
    self.view = pagingScrollView;

    // TODO ? Prepare to tile content
    recycledPages = [[NSMutableSet alloc] init];
    visiblePages  = [[NSMutableSet alloc] init];
    [self processPages];
}


- (void)processPages {

    // Calculate which pages are visible
    CGRect visibleBounds = pagingScrollView.bounds;
    NSLog(@"PhotoViewController - processPages : frame = %@", NSStringFromCGRect(pagingScrollView.frame));
    NSLog(@"pagingScrollView bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
    NSLog(@"and contentSize = %@", NSStringFromCGSize(pagingScrollView.contentSize));

    int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds));
    int lastNeededPageIndex  = floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));
    firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
    lastNeededPageIndex  = MIN(lastNeededPageIndex, [dataSource imageCount] - 1);

    if (lastNeededPageIndex >= 0) {

        // Recycle no-longer-visible pages 
        for (ImageScrollView *page in visiblePages) {
            if (page.index < firstNeededPageIndex || page.index > lastNeededPageIndex) {
                [recycledPages addObject:page];
                [page removeFromSuperview];
            }
        }
        [visiblePages minusSet:recycledPages];

        // add missing pages
        for (int index = firstNeededPageIndex; index <= lastNeededPageIndex; index++) {
            if (![self isDisplayingPageForIndex:index]) {
                ImageScrollView *page = [self dequeueRecycledPage];
                if (page == nil) {
                    page = [[[ImageScrollView alloc] init] autorelease];
                }
                [self configurePage:page forIndex:index];
                NSLog(@"PhotoViewController - processPage 2 : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
                [pagingScrollView addSubview:page];
                NSLog(@"PhotoViewController - processPage 3 : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
                [visiblePages addObject:page];
            }
        }
    }
}

- (ImageScrollView *)dequeueRecycledPage {
    ImageScrollView *page = [recycledPages anyObject];
    if (page) {
        [[page retain] autorelease];
        [recycledPages removeObject:page];
    }
    return page;
}

- (BOOL)isDisplayingPageForIndex:(NSUInteger)index {
    BOOL foundPage = NO;
    for (ImageScrollView *page in visiblePages) {
        if (page.index == index) {
            foundPage = YES;
            break;
        }
    }
    return foundPage;
}

- (void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index {
    page.index = index;
    page.frame = [self frameForPageAtIndex:index];

    NSLog(@"PhotoViewController - configurePage : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));

    [page displayImage:[dataSource imageForImageId:index]];

    NSLog(@"PhotoViewController - configurePage 2 : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
}


#pragma mark -
#pragma mark ScrollView delegate methods

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    [self processPages];
}


#pragma mark -
#pragma mark  Frame calculations
#define PADDING  10

- (CGRect)frameForPagingScrollView {
    CGRect frame = [[UIScreen mainScreen] bounds];
    frame.origin.x -= PADDING;
    frame.size.width += (2*PADDING);
    return frame;
}

- (CGRect)frameForPageAtIndex:(NSUInteger)index {
    CGRect pagingScrollViewFrame = [self frameForPagingScrollView];

    CGRect pageFrame = pagingScrollViewFrame;
    pageFrame.size.width -= (2 * PADDING);
    pageFrame.origin.x = (pagingScrollViewFrame.size.width * index) + PADDING;
    //pageFrame.origin.x = (pagingScrollViewFrame.size.width * index) - (PADDING*index*2);
    return pageFrame;
}

ImageScrollView.h

@interface ImageScrollView : UIScrollView <UIScrollViewDelegate> {
    UIView        *imageView;
    NSUInteger     index;
}
@property (assign) NSUInteger index;

- (void)displayImage:(UIImage *)image;
//- (void)displayTiledImageNamed:(NSString *)imageName size:(CGSize)imageSize;
- (void)configureForImageSize:(CGSize)imageSize;

ImageScrollView.m

- (void)layoutSubviews 
{
    [super layoutSubviews];

    imageView.backgroundColor = [UIColor greenColor];
    self.backgroundColor = [UIColor blueColor];

    // center the image as it becomes smaller than the size of the screen

    CGSize boundsSize = self.bounds.size;
    CGRect frameToCenter = imageView.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;

    imageView.frame = frameToCenter;
    NSLog(@"imageView frame = %@", NSStringFromCGRect(frameToCenter));

    if ([imageView isKindOfClass:[TilingView class]]) {
        // to handle the interaction between CATiledLayer and high resolution screens, we need to manually set the
        // tiling view's contentScaleFactor to 1.0. (If we omitted this, it would be 2.0 on high resolution screens,
        // which would cause the CATiledLayer to ask us for tiles of the wrong scales.)
        imageView.contentScaleFactor = 1.0;
    }
}

#pragma mark -
#pragma mark UIScrollView delegate methods

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return imageView;
}

#pragma mark -
#pragma mark Configure scrollView to display new image (tiled or not)

- (void)displayImage:(UIImage *)image
{
    // clear the previous imageView
    [imageView removeFromSuperview];
    [imageView release];
    imageView = nil;

    // reset our zoomScale to 1.0 before doing any further calculations
    self.zoomScale = 1.0;

    // make a new UIImageView for the new image
    imageView = [[UIImageView alloc] initWithImage:image];
    [self addSubview:imageView];

    [self configureForImageSize:[image size]];
}

- (void)configureForImageSize:(CGSize)imageSize 
{
    CGSize boundsSize = [self bounds].size;

    // set up our content size and min/max zoomscale
    CGFloat xScale = boundsSize.width / imageSize.width;    // the scale needed to perfectly fit the image width-wise
    CGFloat yScale = boundsSize.height / imageSize.height;  // the scale needed to perfectly fit the image height-wise
    CGFloat minScale = MIN(xScale, yScale);                 // use minimum of these to allow the image to become fully visible

    // on high resolution screens we have double the pixel density, so we will be seeing every pixel if we limit the
    // maximum zoom scale to 0.5.
    CGFloat maxScale = /*1.0 / */[[UIScreen mainScreen] scale];

    // don't let minScale exceed maxScale. (If the image is smaller than the screen, we don't want to force it to be zoomed.) 
    if (minScale > maxScale) {
        minScale = maxScale;
    }

    self.contentSize = imageSize;
    self.maximumZoomScale = maxScale;
    self.minimumZoomScale = minScale;
    self.zoomScale = minScale;  // start out with the content fully visible
}

Моя проблема заключается в том, что pagingScrollView смещается в начало координат (0, -64) пикселей(высота строки состояния + навигационная панель, я полагаю), когда я впервые загружаю экземпляр PhotoViewController.Это приводит к перепутанному интерфейсу, в котором ImageScrollView появляется ниже навигационной панели (origin (0, 0)) и может затем быть прокручен вверх и вниз, даже когда его высота меньше, чем экран.

СНекоторые журналы и точки останова. Мне удалось определить, что границы pagingScrollView в начале процесса загрузки подходят.Они меняются, когда я масштабирую изображение ImageScrollView, чтобы соответствовать экрану.Это приводит к вызову viewForZoomingInScrollView, а затем к методам scrollViewDidScroll.PagingScrollView смещается во время этих вызовов.

Я пытался установить смещение вручную, но когда я делаю это в processPages, scrollView больше не может подпрыгивать вверх и вниз ...

Любая помощь будетприветствуется!

Ура

PB

Ответы [ 4 ]

6 голосов
/ 24 сентября 2010

В вашем конкретном случае (т. Е. PhotoViewController помещается в стек UINavigationController) - навигационные панели добавляют contentInset к PhotoViewController представлению прокрутки.Это все лучше объяснить здесь и здесь .

Таким образом, представление PhotoViewController не плотно прилегает к границам вашего окна и, следовательно, имеет пространство для прокрутки во всех направлениях.

Я нашел 2 возможных решения вашей проблемы.

1 - Вам необходимо вручную настроить contentInset вашего pagingScrollView, чтобы компенсировать высоту панели навигации и строки состояния.Добавьте это к PhotoViewController:

- (void)viewDidLoad {
    [super viewDidLoad];

    CGFloat topOffset = self.navigationController.navigationBar.frame.size.height + [[UIApplication sharedApplication] statusBarFrame].size.height;
    pagingScrollView.contentInset = UIEdgeInsetsMake(-topOffset, 0.0, 0.0, 0.0);
}

ИЛИ

2 - Так как только представления прокрутки имеют contentInset, оберните pagingScrollView в простой UIView:

- (void)loadView {    
    [self setWantsFullScreenLayout:YES];

    CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
    photoView = [[UIView alloc] initWithFrame:pagingScrollViewFrame];
    pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];

    // ... configure the pagingScrollView

    [photoView addSubview:pagingScrollView];
    self.view = photoView;

    // ...
}

Надеюсь, это поможет!

0 голосов
/ 31 января 2016

Просто установите вкладку Adjust Scroll View для контроллера представления в значение false из раскадровки.

0 голосов
/ 13 апреля 2012

Основные параметры, которые необходимо установить, следующие в вашем контроллере представления.Используйте флаги автоматического изменения размера при просмотре контента.Включение следующих флагов увеличит размер вашего контроллера представления до полного размера экрана.Я выполняю следующее в viewWillAppear.

- (void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

    [self setWantsFullScreenLayout:YES]; // if you want to underlap status
    self.navigationController.navigationBar.translucent = YES; // underlap nav controller
    self.toolbar.translucent = YES; // if you have a toolbar.
}

Более подробную информацию можно найти здесь в документах Apple:

http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/NavigationControllers.html#//apple_ref/doc/uid/TP40011313-CH2

, если вы выполняли какие-либо действия для установки границ фрейма в представлении содержимого, я быудалите весь этот код, потому что выше должно позаботиться об этом за вас.

0 голосов
/ 15 сентября 2010

У Three20 действительно хорошая реализация. Если вам нужна какая-то необычная функция, она только адаптирует код для вашей собственной необходимости.

Вся тяжелая работа уже сделана. Хотя, если вы все еще хотите реализовать свою собственную версию, хотя бы взгляните на код Three20 и проверьте, как они делают то, чего вы пытаетесь достичь.

Как это выглядит: http://farm4.static.flickr.com/3432/3378117315_3bf905bdb6_o.jpg

Исходный код: http://github.com/facebook/three20

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...