Разрыв между страницами в приложении для фотографий в UIScrollView с помощью pagingEnabled - PullRequest
23 голосов
/ 11 мая 2009

UIScrollView в режиме подкачки предполагает, что страницы расположены рядом друг с другом, без пропусков. Однако, если вы откроете фотографию в приложении «Фотографии» и проведете по фотографиям, вы увидите, что между страницами есть некоторый промежуток. Я тоже хочу эти пробелы.

Я ищу существующие решения, если таковые имеются, или какие-то более причудливые идеи по реализации пробелов в страницах помимо той, которую я объяснил ниже. Или, может быть, есть какой-то очевидный простой способ, которого мне не хватает?

Чтобы быть ясным: я хочу, чтобы разрыв был виден только при прокрутке, поэтому я не могу просто вставить содержимое страницы.


Мой план состоит в том, чтобы попытаться переместить содержимое страницы изнутри обратного вызова scrollViewDidScroll, чтобы (при условии, что вы прокручивали вправо), первоначально целевая страница немного смещалась вправо от ее границ страницы, и к тому времени Вы попадаете на целевую страницу, она возвращается в нужное место, а исходная страница немного смещена влево от своих границ. (Или, возможно, вместо того, чтобы что-то перемещать непрерывно, мне лучше сместить смещения, скажем, точно посередине между страницами.)

Я являюсь автором статьи ScrollingMadness + пример , на которую я ссылался здесь. Я реализовал прогамматическое масштабирование и получил масштабирование в фотографии + прокрутка, работающие вместе с постраничным переходом между фотографиями. Так что я знаю, как играть с UIScrollView, и ищу продвинутые вещи.

Пожалуйста, не указывайте мне на TTScrollView. Я уже указывал на это многим, но считаю, что это слишком далеко от нативного поведения UIScrollView, и не хочу использовать его в своих проектах.

Ответы [ 8 ]

27 голосов
/ 12 мая 2009

Обратите внимание, что этот ответ довольно старый. Основная концепция все еще работает, но Вы не должны жестко кодировать размеры представления в iOS7 и 8. Даже если вы игнорируете этот совет, вы не должны использовать 480 или 330.

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

#define kViewFrameWidth 330; // i.e. more than 320

CGRect scrollFrame;
scrollFrame.origin.x = 0;
scrollFrame.origin.y = 0; 
scrollFrame.size.width = kViewFrameWidth;
scrollFrame.size.height = 480;

UIScrollView* myScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
myScrollView.bounces = YES;
myScrollView.pagingEnabled = YES;
myScrollView.backgroundColor = [UIColor redColor];

UIImage* leftImage = [UIImage imageNamed:@"ScrollTestImageL.png"];
UIImageView* leftView = [[UIImageView alloc] initWithImage:leftImage];
leftView.backgroundColor = [UIColor whiteColor];
leftView.frame = CGRectMake(0,0,320,480);

UIImage* rightImage = [UIImage imageNamed:@"ScrollTestImageR.png"];
UIImageView* rightView = [[UIImageView alloc] initWithImage:rightImage];
rightView.backgroundColor = [UIColor blackColor];
rightView.frame = CGRectMake(kViewFrameWidth * 2,0,320,480);

UIImage* centerImage = [UIImage imageNamed:@"ScrollTestImageC.png"];
UIImageView* centerView = [[UIImageView alloc] initWithImage:centerImage];
centerView.backgroundColor = [UIColor grayColor];
centerView.frame = CGRectMake(kViewFrameWidth,0,320,480);

[myScrollView addSubview:leftView];
[myScrollView addSubview:rightView];
[myScrollView addSubview:centerView];

[myScrollView setContentSize:CGSizeMake(kViewFrameWidth * 3, 480)];
[myScrollView setContentOffset:CGPointMake(kViewFrameWidth, 0)];

[leftView release];
[rightView release];
[centerView release];

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

22 голосов
/ 18 июля 2009

Так что мне не хватает «представителя», чтобы оставить комментарий к ответу выше. Этот ответ правильный, но есть БОЛЬШАЯ проблема, о которой следует знать:

Если вы используете UIScrollView в viewController, который является частью UINavigationController, контроллер навигации изменит размер кадра вашего scrollView.

То есть у вас есть приложение, которое использует UINavigationController для переключения между различными представлениями. Вы нажимаете viewController, у которого есть scrollView, и вы создаете этот scrollView в методе viewController -init. Вы назначаете ему кадр (0, 0, 340, 480).

Теперь перейдите к методу -viewDidAppear вашего viewController, получите кадр созданного вами scrollView. Вы увидите, что ширина была уменьшена до 320 пикселей. Таким образом, пейджинг не будет работать правильно. Вы ожидаете, что scrollView переместится на 340 пикселей, но вместо этого он переместится на 320.

UINavigationController немного печально известен тем, что возится с подпредставлениями. Он перемещает их и изменяет их размер для размещения панели навигации. Короче говоря, это не командный игрок - особенно в этом случае. В других местах в Интернете рекомендуется не использовать UINavigationController, если вам нужен точный контроль размера и местоположения ваших представлений. Вместо этого они предлагают создать собственный класс navigationController на основе UINavigationBar.

Ну, это тонна работы. К счастью, есть более простое решение: установите рамку scrollView в методе -viewDontAppear вашего viewController. На этом этапе UINavigationController завершает работу с кадром, поэтому вы можете сбросить его до того, каким он должен быть, и scrollView будет вести себя правильно.

Это актуально для OS 3.0. Я не проверял 3.1 или 2.2.1. Я также подал в Apple отчет об ошибке, предложив, чтобы они изменили UINavigationController с помощью BOOL, такого как «-shouldAutoarrangeSubviews», чтобы мы могли сохранить этот класс своими грязными руками от подпредставлений.

Пока это не произойдет, приведенное выше исправление даст вам пробелы в разбивке по страницам на UIScrollView в UINavigationController.

7 голосов
/ 20 июня 2010

Apple выпустила видео сессий WWDC 2010 для всех участников программы для разработчиков iphone. Одна из обсуждаемых тем - как они создали приложение для фотографий !!! Они шаг за шагом создают очень похожее приложение и сделали весь код бесплатным.

Он также не использует приватный API. Вот ссылка на пример загрузки кода. Вам, вероятно, понадобится войти, чтобы получить доступ.

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

И вот ссылка на страницу 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

4 голосов
/ 12 июня 2009

Способ сделать это, как вы сказали, сочетание нескольких вещей.

Если вы хотите, чтобы промежуток между изображениями составлял 20 пикселей, вам необходимо:

Сначала увеличьте общую ширину вида прокрутки на 20 пикселей и переместите влево на 10 пикселей.

Во-вторых, когда вы размещаете xLoc своих изображений, добавьте 20 пикселей для каждого изображения, чтобы они были на расстоянии 20 пикселей друг от друга. В-третьих, установите начальный xLoc ваших изображений на 10 пикселей вместо 0 пикселей.

В-четвертых, убедитесь, что вы установили размер содержимого для просмотра с прокруткой, чтобы добавить 20 пикселей для каждого изображения. Так что, если у вас есть изображения kNumImages, и каждое из них имеет вид kScrollObjWidth, то вы идете так:

[scrollView setContentSize:CGSizeMake((kNumImages * (kScrollObjWidth+20)),  kScrollObjHeight)];

После этого должно сработать!

0 голосов
/ 30 апреля 2014

Чтобы избежать путаницы с рамкой UIScrollView, вы можете создать подкласс UIScrollView и переопределить layoutSubviews, чтобы применить смещение к каждой странице.

Идея основана на следующих наблюдениях:

  1. Когда zoomScale! = 1, смещение равно нулю, когда оно находится у левого / правого края
  2. Когда zoomScale == 1, смещение равно нулю, когда оно находится в видимом центре прямоугольника

Затем получается следующий код:

- (void) layoutSubviews
{
    [super layoutSubviews];

    // Find a reference point to calculate the offset:
    CGRect bounds = self.bounds;
    CGFloat pageGap = 8.f;
    CGSize pageSize = bounds.size;
    CGFloat pageWidth = pageSize.width;
    CGFloat halfPageWidth = pageWidth / 2.f;
    CGFloat scale = self.zoomScale;
    CGRect visibleRect = CGRectMake(bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale);
    CGFloat totalWidth = [self contentSize].width / scale;
    CGFloat scrollWidth = totalWidth - visibleRect.size.width;
    CGFloat scrollX = CGRectGetMidX(visibleRect) - visibleRect.size.width / 2.f;
    CGFloat scrollPercentage = scrollX / scrollWidth;
    CGFloat referencePoint = (totalWidth - pageWidth) * scrollPercentage + halfPageWidth;

    // (use your own way to get all visible pages, each page is assumed to be inside a common container)
    NSArray * visiblePages = [self visiblePages];

    // Layout each visible page:
    for (UIView * view in visiblePages)
    {
        NSInteger pageIndex = [self pageIndexForView:view]; // (use your own way to get the page index)

        // make a gap between pages
        CGFloat actualPageCenter = pageWidth * pageIndex + halfPageWidth;
        CGFloat distanceFromRefPoint = actualPageCenter - referencePoint;
        CGFloat numOfPageFromRefPoint = distanceFromRefPoint / pageWidth;
        CGFloat offset = numOfPageFromRefPoint * pageGap;
        CGFloat pageLeft = actualPageCenter - halfPageWidth + offset;

        view.frame = CGRectMake(pageLeft, 0.f, pageSize.width, pageSize.height);
    }
}
0 голосов
/ 30 декабря 2011

Я просто подумал, что добавлю сюда для потомков решение, которое я выбрал. Долгое время я использовал решение Брайана по настройке кадра в -viewDidAppear, и это сработало блестяще. Однако, поскольку iOS представила многозадачность, я столкнулся с проблемой, когда рамка просмотра прокрутки изменяется, когда приложение возобновляет работу из фона. В этом случае -viewDidAppear не вызывался, и я не смог найти метод делегата, который был бы вызван в нужное время, чтобы отменить изменение. Поэтому я решил сделать мой вид прокрутки подвидом моего View Viewler, и это, похоже, решило проблему. Это также имеет то преимущество, что вам не нужно использовать -viewDidAppear для смены фрейма - вы можете сделать это сразу после создания прокрутки. Мой вопрос здесь содержит подробности, но я также опубликую их здесь:

CGRect frame = CGRectMake(0, 0, 320, 460);
scrollView = [[UIScrollView alloc] initWithFrame:frame];

// I do some things with frame here

CGRect f = scrollView.frame;
f.size.width += PADDING; // PADDING is defined as 20 elsewhere
scrollView.frame = f;

[self.view addSubview:scrollView];
0 голосов
/ 12 мая 2009

Может быть, вы хотите попробовать свойство contentInset UIScrollView?

myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);
0 голосов
/ 11 мая 2009

Это всего лишь догадка, поэтому извиняюсь, если полностью ошибаюсь, но возможно ли, что contentSize просто немного шире, чем ширина экрана.

Затем в представлении отображается правильная информация о ширине экрана, а UIScrollView позаботится об остальном?

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