UIScrollView contentSize не работает


ставлю UIScrollView в моем пере view, и связал его с an IBOutlet собственность.

теперь, когда я делаю это в мой viewDidLoad метод, похоже, не влияет на contentSize:

self.sv.backgroundColor = [UIColor yellowColor]; // this works
CGSize size =  CGSizeMake(1000.0, 1000.0); 
[self.sv setContentSize:size]; // this does not

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

14 54

14 ответов:

у меня была та же проблема. Авто макет для UIScrollView перепутались.

работа вокруг: положите все в UIScrollView в другой UIView, и положить, что UIView как единственный ребенок UIScrollView. Затем вы можете использовать автоматическую компоновку.

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

я попробовал viewWillLayoutSubviews для обновления содержимого scrollView, это сработало для меня.

- (void)viewDidLayoutSubviews
{
  [self.bgScrollView setContentSize:CGSizeMake(320, self.view.frame.size.height* 1.5)];
}

Apple Doc

-(void)viewDidLayoutSubviews

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

Обсуждение

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

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

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

супер простой способ использовать AutoLayout с UIScrollViews внутри Interface Builder:

Шаг 1: создать UIScrollView

Шаг 2: создать UIView это дитя вашего вида прокрутки вот так:

-UIScrollView
---UIView
-----Your other content

(мы будем называть это contentView).

Шаг 3: в инспекторе размера, дайте этому виду высоту и ширину (скажем, 320x700).

Шаг 4 (с помощью автозапуска): создать однозначные ограничения от вашего contentView к своему супервизору (the UIScrollView): соедините 4 края (верхний, ведущий, задний, нижний), затем дайте ему определенную ширину и высоту, которую вы хотите прокрутить.

например: если ваш вид прокрутки охватывает весь экран, вы можете дать вашему виду содержимого ширину [ширина устройства] и высоту 600; затем он установит содержимое размер UIScrollView в матче.

или:

Шаг 4 (не используя автозапуск): соединить обе эти новые элементы управления для вашего контроллера представления с помощью ПБ (Ctrl+перетаскивание из каждого управления для вашего контроллера представления .ч осуществлению@). Предположим, что каждый из них называется scrollView и contentView, соответственно. Это должно выглядеть так:

@interface YourViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
@property (strong, nonatomic) IBOutlet UIView *contentView;

@end

Шаг 5 (не используя автозапуск): в контроллере вида .H-Файл Добавить (на самом деле, переопределить) следующий метод:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.scrollView.contentSize = self.contentView.frame.size;
}

здесь есть две проблемы. (1) viewDidLoad слишком рано; вы должны ждать, пока не произойдет макет. (2) Если вы хотите использовать autolayout с scrollview, который исходит из пера, то либо вы должны использовать ограничения, чтобы полностью описать размер contentSize (и тогда вы не устанавливаете contentSize в коде вообще), или, если вы хотите установить его в коде, вы должны запретить ограничения на подвиды scrollview от диктовки contentSize. Это похоже на тебя хотелось бы сделать последнее. Для этого вам нужен UIView, который выступает в качестве единственного подвида верхнего уровня scrollview, и в коде вы должны установить его в не используйте автозапуск, включив его autoresizingMask и устранение других внешних ограничений. Я показываю пример того, как это сделать, здесь:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch20p573scrollViewAutoLayout/ch20p573scrollViewAutoLayout/ViewController.m

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

используйте этот код. ScrollView setContentSize должен называться асинхронным в главном потоке.

- (void)viewDidLayoutSubviews
    {

    [super viewDidLayoutSubviews];

    dispatch_async(dispatch_get_main_queue(), ^
                   {
                       CGRect contentRect = CGRectZero;
                       for (UIView *view in scrollView.subviews)
                               contentRect = CGRectUnion(contentRect, view.frame);

                       contentRect.size.height=contentRect.size.height;
                       scrollView.contentSize = contentRect.size;
                   });
    }

вы можете использовать эти строки кода в вашем *.файл m

- (void)viewDidLoad{
   [scroll setContentSize:CGSizeMake(320, 800)]   ;
   [scroll setScrollEnabled:TRUE];
   [scroll setShowsVerticalScrollIndicator:NO];
   [scroll setShowsHorizontalScrollIndicator:YES];
}    

для этого вам нужно взять свойство IBOutlet UIScrollView в свой *.H-файл таким образом:

IBOutlet UIScrollView *scroll;

и подключить это из раскадровки.

или

вы можете использовать этот метод в вашей *.файл м:

-(void)viewDidLayoutSubviews 
{
  [scroll setContentSize:CGSizeMake(320, self.view.frame.size.height* 1.5)];
   // this will pick height automatically from device's height and multiply it with 1.5  
}

Это решение работает для меня xcode-5, xcode-6, xcode-6.1, xcode-6.2

установка contentSize в viewDidAppear критическое.

но у меня также была вариация того, что работало на 3,5-дюймовом экране и на 4-дюймовом экране. 4-дюймовый экран работал, более старый-нет. Оба iOS 7. Странно-это еще мягко сказано!

Я никогда не мог получить автоматический макет на основе ограничений на работу. Поскольку мое представление уже было подклассом UIScrollView, я решил его путем переопределения setContentView: и игнорирования автоматических макетов нулевой высоты setContentSize: message.

@interface MyView : UIScrollView {}
@end

@implementation MyView
- (void)setContentSize:(CGSize)aSize {
    if (aSize.height > 0)
        [super setContentSize:aSize];
}
@end

раньше я программно настраивал uiscrollview, пока не посмотрел следующий замечательный учебник, шаг за шагом, как заставить uiscrollview и uiview работать:https://www.youtube.com/watch?v=PgeNPRBrB18

после просмотра видео вы начнете любить Interface Builder я уверен.

голосовать

если вы используете AutoLayout очень простой способ установить contentSize на UIScrollView - это просто, чтобы добавить что-то вроде этого:

CGFloat contentWidth = YOUR_CONTENT_WIDTH;

NSLayoutConstraint *constraintWidth = 
 [NSLayoutConstraint constraintWithItem:self.scrollView 
                              attribute:NSLayoutAttributeTrailing 
                              relatedBy:NSLayoutRelationEqual 
                                 toItem:self.scrollView 
                              attribute:NSLayoutAttributeLeading 
                             multiplier:1 
                               constant:contentWidth];

[self.scrollView addConstraint:constraintWidth];

по-прежнему не прокручивается, когда динамическая высота меток превышает высоту просмотра.

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

enter image description here

внутри моего представления контента у меня есть изображение и 3 метки под ним. Каждая метка настраивает свою собственную высоту в зависимости от того, сколько в них текста (для этого они установлены в word-wrap и numberoflines = 0).

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

чтобы исправить это, я сформулировал я необходимо установить Нижний космос к контейнеру ограничение между моей нижней меткой и contentview и дал ему значение 40 (выбран произвольно, чтобы дать ему хороший запас внизу). Теперь это означает, что мой contentview регулирует свою высоту так, чтобы между нижней частью последней метки и самим собой и он прокручивается отлично!

Ура!

попробуйте это...
добавьте все ограничения, как вы делаете для UIView(смотрите скриншот моего ViewControler в раскадровке)
enter image description here
Теперь начинается трюк. выберите последний объект и выберите его нижнее ограничение. (см. скриншот выше, нижнее ограничение кнопки Instagram(желтая линия)) и измените постоянный размер инспектора, как на скриншоте ниже.

enter image description here

Я требую Константа=8 но вы можете изменить согласно вашим требованиям. эта константа-это пространство между нижней частью этой оранжевой кнопки и прокруткой.

EDIT

убедитесь в иерархии вашего представления .

0) ViewController.вид (дополнительно)
1) UIScrollView
2) UIView (переименовать как "contentView")
3) UIView (это представление-ваш контент, который сделает scrollView прокрутки)

Я получил автозапуск для работы с разбиением на страницы прокрутки, страницы которых занимают всю ширину экрана. страницы автоматически изменяются в соответствии с размером прокрутки. Я не проверял это для просмотра прокрутки меньшей ширины, но комментирую, если это работает-я верю, что это должно быть. Targeted для iOS 9, написал код в Swift 2, использовал смесь IB и пользовательского кода в awakeFromNib.

действия:

  • определение полноэкранной прокрутки вид.
  • в представлении прокрутки добавьте UIView (я назвал шахту contentView) чьи верхние, задние, нижние и передние края для вида прокрутки равны нулю; высота равна виду прокрутки;но ширина-это ширина вида прокрутки, умноженная на количество страниц. если вы делаете это визуально, вы увидите, что ваше представление контента выходит за пределы вашего представления прокрутки в Inteface Builder.
  • для каждой "страницы" внутри contentView, добавить правила автозапуска, чтобы положить их бок о бок друг с другом, но самое главное, дайте каждому из них ограничение, чтобы их ширина была равна ширине представления прокрутки, а не представлению содержимого.

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

на мой взгляд контроллер:

override func loadView() {
    self.view = self.customView
}

override func viewDidLoad() {
super.viewDidLoad()

self.embedChildViewController(self.addExpenseVC, toView: self.customView.contentView, fillSuperview: false)
self.embedChildViewController(self.addCategoryVC, toView: self.customView.contentView, fillSuperview: false)
self.customView.setupLayoutRulesForPages(self.addExpenseVC.view, secondPage: self.addCategoryVC.view)
}

мой пользовательский вид:

class __AMVCView: UIView {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var contentView: UIView!
    @IBOutlet weak var pageControl: UIPageControl!

    override func awakeFromNib() {
        super.awakeFromNib()

        self.scrollView.pagingEnabled = true
        self.scrollView.bounces = true
        self.scrollView.showsHorizontalScrollIndicator = false
        self.scrollView.showsVerticalScrollIndicator = false

        self.pageControl.numberOfPages = 2

        self.contentView.backgroundColor = UIColor.blueColor()
        self.scrollView.backgroundColor = UIColor.clearColor()
        self.backgroundColor = UIColor.blackColor()
    }

    func setupLayoutRulesForPages(firstPage: UIView, secondPage: UIView) {
        guard self.contentView.subviews.contains(firstPage) && self.contentView.subviews.contains(secondPage)
            else {
                return
        }

        let rules = [
            "H:|-0-[firstPage]-0-[secondPage]-0-|",
            "V:|-0-[firstPage]-0-|",
            "V:|-0-[secondPage]-0-|"
        ]
        let views = [
            "firstPage" : firstPage,
            "secondPage" : secondPage
        ]
        let constraints = NSLayoutConstraint.constraintsWithVisualFormatArray(rules, metrics: nil, views: views)

        UIView.disableAutoresizingMasksInViews(firstPage, secondPage)
        self.addConstraints(constraints)

        // Add the width Autolayout rules to the pages.
        let widthConstraint = NSLayoutConstraint(item: firstPage, attribute: .Width, relatedBy: .Equal, toItem: self.scrollView, attribute: .Width, multiplier: 1, constant: 0)
        self.addConstraint(widthConstraint)
    }

}