Как мне автоматически изменить размер UIScrollView, чтобы соответствовать его содержимому

Есть ли способ сделать UIScrollView автоматическую настройку высоты (или ширины) содержимого, которое он прокручивает?

Что-то вроде:

[scrollView setContentSize:(CGSizeMake(320, content.height))];

Ответ 1

Лучший метод, с которым я когда-либо сталкивался, обновлял размер содержимого UIScrollView на основе его вложенных подпредставлений:

Objective-C

CGRect contentRect = CGRectZero;

for (UIView *view in self.scrollView.subviews) {
    contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;

стриж

var contentRect = CGRect.zero

for view in mainScrollView.subviews {
   contentRect = contentRect.union(view.frame)
}
mainScrollView.contentSize = contentRect.size

Ответ 2

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

Сделайте это с чем-то вроде

CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
   scrollViewHeight += view.frame.size.height;
}

[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];

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

Ответ 3

Решение, если вы используете автоматический макет:

  • Установите translatesAutoresizingMaskIntoConstraints в NO для всех рассмотренных видов.

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

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

Источник: https://developer.apple.com/library/ios/technotes/tn2154/_index.html

Ответ 4

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

+ (CGFloat) bottomOfLowestContent:(UIView*) view
{
    CGFloat lowestPoint = 0.0;

    BOOL restoreHorizontal = NO;
    BOOL restoreVertical = NO;

    if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
    {
        if ([(UIScrollView*)view showsHorizontalScrollIndicator])
        {
            restoreHorizontal = YES;
            [(UIScrollView*)view setShowsHorizontalScrollIndicator:NO];
        }
        if ([(UIScrollView*)view showsVerticalScrollIndicator])
        {
            restoreVertical = YES;
            [(UIScrollView*)view setShowsVerticalScrollIndicator:NO];
        }
    }
    for (UIView *subView in view.subviews)
    {
        if (!subView.hidden)
        {
            CGFloat maxY = CGRectGetMaxY(subView.frame);
            if (maxY > lowestPoint)
            {
                lowestPoint = maxY;
            }
        }
    }
    if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
    {
        if (restoreHorizontal)
        {
            [(UIScrollView*)view setShowsHorizontalScrollIndicator:YES];
        }
        if (restoreVertical)
        {
            [(UIScrollView*)view setShowsVerticalScrollIndicator:YES];
        }
    }

    return lowestPoint;
}

Ответ 5

Вот признанный ответ в быстром тем, кто слишком ленив, чтобы преобразовать его:)

var contentRect = CGRectZero
for view in self.scrollView.subviews {
    contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size

Ответ 6

Здесь адаптация Swift 3 @leviatan:

EXTENSION

import UIKit


extension UIScrollView {

    func resizeScrollViewContentSize() {

        var contentRect = CGRect.zero

        for view in self.subviews {

            contentRect = contentRect.union(view.frame)

        }

        self.contentSize = contentRect.size

    }

}

ИСПОЛЬЗОВАНИЕ

scrollView.resizeScrollViewContentSize()

Очень проста в использовании!

Ответ 7

Следующее расширение будет полезно в Swift.

extension UIScrollView{
    func setContentViewSize(offset:CGFloat = 0.0) {
        // dont show scroll indicators
        showsHorizontalScrollIndicator = false
        showsVerticalScrollIndicator = false

        var maxHeight : CGFloat = 0
        for view in subviews {
            if view.isHidden {
                continue
            }
            let newHeight = view.frame.origin.y + view.frame.height
            if newHeight > maxHeight {
                maxHeight = newHeight
            }
        }
        // set content size
        contentSize = CGSize(width: contentSize.width, height: maxHeight + offset)
        // show scroll indicators
        showsHorizontalScrollIndicator = true
        showsVerticalScrollIndicator = true
    }
}

Логика одинакова с данными ответами. Тем не менее, он пропускает скрытые представления в UIScrollView и вычисление выполняется после скрытых указателей прокрутки.

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

Ответ 8

Отличное и лучшее решение от @leviathan. Просто перевести на быстрый подход с использованием FP (функционального программирования).

self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), { 
  CGRectUnion($0, $1.frame) 
}.size

Ответ 9

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

float maxHeight = 0;
for (UIView *child in scrollView.subviews) {
    float childHeight = child.frame.origin.y + child.frame.size.height;
    //if child spans more than current maxHeight then make it a new maxHeight
    if (childHeight > maxHeight)
        maxHeight = childHeight;
}
//set content size
[scrollView setContentSize:(CGSizeMake(320, maxHeight))];

Делая вещи таким образом, элементы (subviews) не должны быть уложены непосредственно друг под другом.

Ответ 10

Я придумал другое решение, основанное на решении @emenegro

NSInteger maxY = 0;
for (UIView* subview in scrollView.subviews)
{
    if (CGRectGetMaxY(subview.frame) > maxY)
    {
        maxY = CGRectGetMaxY(subview.frame);
    }
}
maxY += 10;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, maxY)];

В принципе, мы выясняем, какой элемент наиболее удален в представлении и добавляет отладку 10px на дно.

Ответ 11

Так как scrollView может иметь другие scrollViews или другое дерево inDepth subViews, то рекурсивно работать рекурсивно. введите описание изображения здесь

Swift 2

extension UIScrollView {
    //it will block the mainThread
    func recalculateVerticalContentSize_synchronous () {
        let unionCalculatedTotalRect = recursiveUnionInDepthFor(self)
        self.contentSize = CGRectMake(0, 0, self.frame.width, unionCalculatedTotalRect.height).size;
    }

    private func recursiveUnionInDepthFor (view: UIView) -> CGRect {
        var totalRect = CGRectZero
        //calculate recursevly for every subView
        for subView in view.subviews {
            totalRect =  CGRectUnion(totalRect, recursiveUnionInDepthFor(subView))
        }
        //return the totalCalculated for all in depth subViews.
        return CGRectUnion(totalRect, view.frame)
    }
}

Использование

scrollView.recalculateVerticalContentSize_synchronous()

Ответ 12

Или просто выполните:

int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];

(Это решение было добавлено мной в качестве комментария на этой странице. Получив 19 голосов за этот комментарий, я решил добавить это решение в качестве официального ответа на благо сообщества!)

Ответ 13

Размер зависит от содержимого, загруженного внутри него, и параметров отсечения. Если это текстовое представление, то это также зависит от обертывания, количества строк текста, размера шрифта и т.д. И т.д. Вы почти невозможно вычислить себя. Хорошей новостью является то, что она вычисляется после загрузки представления и в viewWillAppear. До этого все неизвестные и размер контента будут такими же, как размер кадра. Но в методе viewWillAppear и после (например, viewDidAppear) размер содержимого будет фактическим.

Ответ 14

Копирование кода Richy Я создал настраиваемый класс UIScrollView, который автоматизирует полное изменение содержимого!

SBScrollView.h

@interface SBScrollView : UIScrollView
@end

SBScrollView.m:

@implementation SBScrollView
- (void) layoutSubviews
{
    CGFloat scrollViewHeight = 0.0f;
    self.showsHorizontalScrollIndicator = NO;
    self.showsVerticalScrollIndicator = NO;
    for (UIView* view in self.subviews)
    {
        if (!view.hidden)
        {
            CGFloat y = view.frame.origin.y;
            CGFloat h = view.frame.size.height;
            if (y + h > scrollViewHeight)
            {
                scrollViewHeight = h + y;
            }
        }
    }
    self.showsHorizontalScrollIndicator = YES;
    self.showsVerticalScrollIndicator = YES;
    [self setContentSize:(CGSizeMake(self.frame.size.width, scrollViewHeight))];
}
@end

Как использовать:
Просто импортируйте файл .h в контроллер просмотра и объявите экземпляр SBScrollView вместо обычного UIScrollView.

Ответ 15

Задайте размер динамического содержимого следующим образом.

 self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);

Ответ 16

Для swift4 с использованием уменьшите:

self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
   return $0.union($1.frame)
}).size

Ответ 17

это действительно зависит от контента: content.frame.height может дать вам то, что вы хотите? Зависит от того, является ли контент единственной вещью или коллекцией вещей.

Ответ 18

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

-(void)adjustContentSizeToFit является общедоступным методом в пользовательском подклассе UIScrollView.

-(void)awakeFromNib {    
    dispatch_async(dispatch_get_main_queue(), ^{
        [self adjustContentSizeToFit];
    });
}

-(void)adjustContentSizeToFit {

    BOOL showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
    BOOL showsHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;

    self.showsVerticalScrollIndicator = NO;
    self.showsHorizontalScrollIndicator = NO;

    CGRect contentRect = CGRectZero;
    for (UIView *view in self.subviews) {
        contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.contentSize = contentRect.size;

    self.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
    self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}

Ответ 19

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

extension UIScrollView {
    func updateContentViewSize() {
        var newHeight: CGFloat = 0
        for view in subviews {
            let ref = view.frame.origin.y + view.frame.height
            if ref > newHeight {
                newHeight = ref
            }
        }
        let oldSize = contentSize
        let newSize = CGSize(width: oldSize.width, height: newHeight + 20)
        contentSize = newSize
    }
}

Ответ 20

почему не одна строка кода?

_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);