it-swarm.com.ru

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

Я поместил UIScrollView в свой перо view и связал его со свойством 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 был таким же, как фрейм. Что происходит? Это начало работать, когда я отключил AutoLayout. Зачем?

54
cannyboy

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

Обходной путь: Поместите все в UIScrollView в другой UIView и поместите этот UIView в качестве единственного потомка UIScrollView. Тогда вы можете использовать Auto Layout.

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

76
yuf

Я попытался viewWillLayoutSubviews обновить scrollView contentSize, у меня это сработало.

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

Apple Doc

-(void)viewDidLayoutSubviews

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

Обсуждение

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

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

65
HDdeveloper

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

19
Jlam

СУПЕР простой способ использовать AutoLayout с UIScrollViews внутри Interface Builder:

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

Шаг 2: Создайте UIView, который является дочерним для вашего вида прокрутки, примерно так:

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

(Мы назовем это contentView).

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

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

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

ИЛИ ЖЕ:

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

@interface YourViewController : UIViewController

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

@end

Шаг 5 (без использования AutoLayout): В файле .h контроллера вида добавьте (собственно, переопределите) следующий метод:

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

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

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

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

13
matt

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

Swift:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    DispatchQueue.main.async {
        var contentRect = CGRect.zero

        for view in self.scrollView.subviews {
           contentRect = contentRect.union(view.frame)
        }

        self.scrollView.contentSize = contentRect.size
    }
}

Цель C:

 - (void)viewDidLayoutSubviews {
     [super viewDidLayoutSubviews];

     dispatch_async(dispatch_get_main_queue(), ^ {
                        CGRect contentRect = CGRectZero;

                        for(UIView *view in scrollView.subviews)
                           contentRect = CGRectUnion(contentRect,view.frame);

                           scrollView.contentSize = contentRect.size;
                       });
}
11
Karen Hovhannisyan

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

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

для этого вам нужно взять свойство IBOutlet UIScrollView в ваш файл * .h следующим образом:

IBOutlet UIScrollView *scroll;

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

Или же,

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

-(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

5
imti

Установка contentSize в viewDidAppear имеет решающее значение. 

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

3
PostCodeism

Если вы используете 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];
1
korovyev

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

После просмотра видео вам наверняка понравится интерфейс Builder. 

Проголосуй

1
oabarca

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

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

 enter image description here

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

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

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

Ура!

1
Guy Lowe

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

@interface MyView : UIScrollView {}
@end

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

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

enter image description here

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

ПРАВКА

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

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

1
Vats

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

Шаги:

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

Пример кода ниже. embedChildViewController - это просто мой удобный метод для добавления дочерних VC - посмотрите на 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)
    }

}
0
Matthew Quiros