Подтвердить что ты не робот

Фотографий, похожий на приложение, между страницами в UIScrollView с pagingEnabled

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

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

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


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

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

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

4b9b3361

Ответ 1

Обратите внимание, что этот ответ довольно старый. Основная концепция все еще работает, но вы не должны быть жесткими размерами кодирования в 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];

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

Ответ 2

Поэтому мне не хватает "репутации", чтобы опубликовать комментарий к ответу выше. Этот ответ правильный, но есть большая проблема, о которой нужно знать:

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

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

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

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

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

Это актуально для ОС 3.0. Я не тестировал 3.1 или 2.2.1. Я также опубликовал отчет об ошибке с Apple, предлагая, чтобы они модифицировали UINavigationController с помощью BOOL, например, "-shouldAutoarrangeSubviews", чтобы мы могли заставить этот класс удерживать свои грязные руки от подсмотров.

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

Ответ 3

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

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

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

И вот ссылка на страницу WWDC iTunes:

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

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

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

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

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

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

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

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

Ответ 5

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

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

Ответ 6

Возможно, вы хотите попробовать свойство UIScrollView contentInset?

myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);

Ответ 7

Я просто подумал, что добавлю сюда для потомства решение, с которым я столкнулся. В течение долгого времени я использовал решение Bryan для настройки рамки в -viewDidAppear, и это сработало блестяще. Однако, поскольку iOS представила многозадачность, у меня возникла проблема, когда рамка просмотра прокрутки изменяется, когда приложение возобновляется с фона. В этом случае -viewDidAppear не вызывался, и я не мог найти метод делегата, который будет вызываться в нужное время, чтобы отменить изменение. Поэтому я решил сделать свой прокруток просмотром подсмотра моего представления View Controller, и это, похоже, устранило проблему. Это также имеет то преимущество, что вам не нужно использовать -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];

Ответ 8

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

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

  • Когда zoomScale!= 1, смещение равно нулю, когда оно находится на левом/правом краю
  • Когда 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);
    }
}