Прокрутка, масштабирование UIScrollView и поворот ориентации интерфейса. Как использовать авторазмер и многое другое

Это должно быть довольно распространенным делом, но я не смог заставить его работать точно.

У меня есть прямоугольный контент. Обычно он умещается в 320x361: портретный режим минус строка состояния минус ad минус панель вкладок.

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

Что мне нужно сделать в Интерфейсном Разработчике и коде, чтобы сделать это? Как мне установить автоматическое изменение размеров для разных видов? Как мне установить contentSize и contentInsets?

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

То, как я это делаю сейчас, правильно на 80%. То есть из 10 вещей, которые он должен делать, он делает 8 из них. Две вещи, которые он делает неправильно:

  1. При увеличении в портретном режиме вы можете прокручивать границы содержимого и видеть черный фон. Это не так уж много, чтобы жаловаться. По крайней мере, вы можете увидеть весь контент. В ландшафтном режиме, увеличенном или уменьшенном, черный фон за краем виден нормально, так как контенту не хватает ширины, чтобы заполнить экран при уровне масштабирования 1:1 (минимум).

  2. Я все еще получаю контент, застрявший на краю, когда он работает на тестовом устройстве под управлением iOS 3.0, но он работает на моем, работающем под управлением 4.x. - На самом деле это было с предыдущим решением. Мой тестер не пробовал последнее решение.

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

Посмотреть иерархию:

  • Посмотреть
    • Scrollview
      • scrollableArea
        • содержание
    • объявление

представление имеет размер 320х411 и имеет все параметры автоматического изменения размера, поэтому соответствует форме экрана

scrollView имеет размер 480 x 361, начинается с начала координат -80,0 и блокируется только сверху и отключает растяжение

scrollableArea имеет размер 480 x 361 и фиксируется слева и сверху. Поскольку scrollView отключает растяжение, маски авторазмера для его подпредставлений не имеют значения, но я все равно скажу вам.

содержимое 320x361, начинается с начала 80,0 и блокируется сверху

Я устанавливаю scrollView.contentSize до 480х361.

shouldAutorotateToInterfaceOrientation поддерживает все ориентации, кроме портрета вверх ногами.

В didRotateFromInterfaceOrientation я устанавливаю нижнюю вставку содержимого 160, если ориентация горизонтальная, сбрасываю на 0, если нет. Я устанавливаю левый и правый индикаторные вставки по 80 каждый, если ориентация портретная, и сбрасываю, если нет.

scrollView.minimumZoomScale = 1.0

scrollView.maximumZoomScale = 2.0

viewForZoomingInScrollView возвращает scrollableArea

4 ответа

// in IB it would be all options activated
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
scrollView.contentSize = content.frame.size; // or bounds, try both

что ты имеешь ввиду scrollableArea?

ваш minZoomScale установлен в 1.0 это хорошо для портретного режима, но не для пейзажа. Поскольку в ландшафте ваша высота меньше, чем в портретной, вам нужно иметь значение меньше, чем 1.0, Для меня я использую эту реализацию и вызываю ее каждый раз, кадр scrollView менялся:

- (void)setMaxMinZoomScalesForCurrentBounds {
    CGSize boundsSize = self.bounds.size; // self is a UIScrollView here
    CGSize contentSize = content.bounds.size;

    CGFloat xScale = boundsSize.width / contentSize.width;
    CGFloat yScale = boundsSize.height / contentSize.height;
    CGFloat minScale = MIN(xScale, yScale);

    if (self.zoomScale < minScale) {
        [self setZoomScale:minScale animated:NO];
    }
    if (minScale<self.maximumZoomScale) self.minimumZoomScale = minScale;
    //[self setZoomScale:minScale animated:YES];
}

- (void)setFrame:(CGRect)rect { // again, this class is a UIScrollView
    [super setFrame:rect];
    [self setMaxMinZoomScalesForCurrentBounds];
}

Когда вы хотите поместить контент (UIView Например, давайте назовем это theViewInstance) в UIScrollView а затем прокрутить / увеличить theViewInstance способ сделать это:

  • theViewInstance следует добавить в качестве подпредставления UIScrollView
  • назначить делегата UIScrollView Создайте экземпляр и реализуйте селектор, чтобы вернуть представление, которое должно использоваться для масштабирования / прокрутки:

    -(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {  
          return theViewInstance;  
    } 
    
  • Задайте для contentSize UIScrollView фрейм theViewInstance по умолчанию:

    scrollView.contentSize=theViewInstance.frame.size;
    

    (Кроме того, допустимые уровни масштабирования могут быть установлены в UIScrollView:)

    scrollView.minimumZoomScale=1.0;
    scrollView.maximumZoomScale=3.0;
    

Это способ увеличения масштаба в UIImage: UIImageView добавляется в UIScrollView, а в реализации UIScrollViewDelegate возвращается UIImageView (как описано здесь, например).

Для поддержки поворота это делается в UIViewController, UIView которого содержит UIScrollView, о котором мы только что говорили.

Если я правильно понимаю, что вы хотите прокрутки с изображением на нем. Для начала он должен быть полноэкранным и иметь возможность увеличения. Кроме того, вы хотите, чтобы он мог вращаться в соответствии с ориентацией.

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

Я оставил немного белой области для баров / пользовательских панелей.

- (void)viewDidLoad
{  
    [super viewDidLoad];

    //first inits and allocs
    scrollView2 = [[UIScrollView alloc] initWithFrame:self.view.frame];
    imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImageName"]];
    [scrollView2 addSubview:imageView];
    [self drawContent]; //refreshing the content
    [self.view addSubview:scrollView2];
}

-(void)drawContent
{
    //this refreshes the screen to the right sizes and zoomscales.
    [scrollView2 setBackgroundColor:[UIColor blackColor]];
    [scrollView2 setCanCancelContentTouches:NO];
    scrollView2.clipsToBounds = YES;
    [scrollView2 setDelegate:self];
    scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;

    [scrollView2 setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
    [scrollView2 setScrollEnabled:YES];

    float minZoomScale;
    float zoomHeight = imageView.frame.size.height / scrollView2.frame.size.height;
    float zoomWidth = imageView.frame.size.width / scrollView2.frame.size.width;

    if(zoomWidth > zoomHeight)
    {
        minZoomScale = 1.0 / zoomWidth;
    }
    else
    {
        minZoomScale = 1.0 / zoomHeight;
    }

    [scrollView2 setMinimumZoomScale:minZoomScale];
    [scrollView2 setMaximumZoomScale:7.5];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations

    if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {

        // Portrait 
        //the 88pxls is the white area that is left for the navbar etc.

        self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.width, self.view.frame.size.height - 88);
        [self drawContent];
    }
    else {

        // Landscape
        //the 88pxls is the white area that is left for the navbar etc.

        self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.height, self.view.frame.size.width);
        [self drawContent];
    }
    return YES;
}

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

Я надеюсь, что это исправит ваши проблемы. Если не оставить комментарий.

Я не думаю, что я понял всю проблему из вашего поста, но вот ответ на то, что я понял.

Насколько я знаю (и работал с UIScrollView), содержимое внутри UIScrollView не автоматически автоматически изменяет размер вместе с UIScrollView.

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

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

Для правильного автоматического изменения размера вы должны изменить contentSize для scrollView (чтобы он знал размер вашего юниверса), но также изменить размер UIView. Я думаю, именно поэтому вы смогли прокрутить и получить этот черный контент. Может быть, вы только что обновили contentSize, но теперь все просмотры контента.

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

Другие вопросы по тегам