Jak Mogę automatycznie rozmiar UIScrollView dopasować zawartość

Czy istnieje sposób na automatyczne dopasowanie UIScrollView do wysokości (lub szerokości) przewijanej zawartości?

Coś w stylu:

[scrollView setContentSize:(CGSizeMake(320, content.height))];
Author: jwerre, 2010-05-31

20 answers

Najlepsza metoda, jaką kiedykolwiek spotkałem, aby zaktualizować Rozmiar zawartości UIScrollView w oparciu o zawarte w niej podviews:

ObjC

CGRect contentRect = CGRectZero;

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

Swift

  var contentRect = CGRect.zero

  for view in mainScrollView.subviews {
     contentRect = contentRect.union(view.frame)
  }
  mainScrollView.contentSize = contentRect.size
 277
Author: leviathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-05 06:03:09

UIScrollView nie zna wysokości swojej zawartości automatycznie. Musisz obliczyć wysokość i szerokość dla siebie

Zrób to z czymś takim

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

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

Ale to działa tylko wtedy, gdy widoki są JEDEN poniżej drugiego. Jeśli masz widok obok siebie, musisz tylko dodać jego wysokość, jeśli nie chcesz, aby zawartość przewijarki była większa niż w rzeczywistości.

 74
Author: emenegro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-18 13:56:05

Dodałem to do odpowiedzi Espuz i JCC. Używa pozycji y podwidywań i nie zawiera pasków przewijania. Edit używa dołu najniższego widoku podrzędnego, który jest widoczny.

+ (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;
}
 35
Author: richy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-25 23:01:54

Rozwiązanie jeśli używasz układu auto:

  • Ustaw translatesAutoresizingMaskIntoConstraints Na NO dla wszystkich widoków.

  • Umieść i rozmiar widoku przewijania z ograniczeniami zewnętrznymi do widoku przewijania.

  • Używaj ograniczeń, aby rozłożyć podwinięcia w widoku przewijania, upewniając się, że ograniczenia są powiązane ze wszystkimi czterema krawędziami widoku przewijania i nie polegają na widoku przewijania, aby uzyskać ich rozmiar.

Źródło: https://developer.apple.com/library/ios/technotes/tn2154/_index.html

 32
Author: Adam Waite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-27 22:17:59

Oto zaakceptowana odpowiedź w języku swift dla każdego, kto jest zbyt leniwy, aby ją nawrócić:)

var contentRect = CGRectZero
for view in self.scrollView.subviews {
    contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
 13
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-16 07:33:47

Dalsze rozszerzenie byłoby pomocne w 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.hidden {
                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
    }
}

Logika jest taka sama z udzielonymi odpowiedziami. Pomija jednak ukryte widoki w UIScrollView, A obliczenia są wykonywane po ustawieniu ukrytych wskaźników przewijania.

Istnieje również opcjonalny parametr funkcji i możesz dodać wartość offsetu, przekazując parametr do funkcji.

 6
Author: gokhanakkurt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-10 19:54:50

Świetne i najlepsze rozwiązanie od @ Lewiatan. Tłumaczenie na język swift z wykorzystaniem podejścia FP (functional programming).

self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), { 
  CGRectUnion($0, $1.frame) 
}.size
 5
Author: othierry42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-27 14:11:33

Oto szybka 3 adaptacja odpowiedzi @ leviatan:

Rozszerzenie

import UIKit


extension UIScrollView {

    func resizeScrollViewContentSize() {

        var contentRect = CGRect.zero

        for view in self.subviews {

            contentRect = contentRect.union(view.frame)

        }

        self.contentSize = contentRect.size

    }

}

Użycie

scrollView.resizeScrollViewContentSize()

Bardzo łatwy w użyciu !

 5
Author: fredericdnd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-08 23:52:15

Możesz uzyskać wysokość zawartości wewnątrz UIScrollView, obliczając, które dziecko "osiąga dalej". Aby to obliczyć, musisz wziąć pod uwagę pochodzenie Y (początek) i Wysokość elementu.

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))];

W ten sposób elementy (podwidywacze)nie muszą być układane jeden pod drugim.

 4
Author: paxx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-21 18:43:15

Wymyśliłem inne rozwiązanie oparte na rozwiązaniu @ 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)];

W zasadzie, możemy dowiedzieć się, który element jest najdalej w dół w widoku i dodaje padding 10px do dołu

 3
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-05 16:12:53

Ponieważ widok przewijania może mieć inne widoki przewijania lub inne drzewo podwidywalne, preferowane jest wykonywanie w głębi rekurencyjnie. Tutaj wpisz opis obrazka

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)
    }
}

Użycie

scrollView.recalculateVerticalContentSize_synchronous()
 3
Author: iluvatar_GR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-22 17:02:51

Lub po prostu zrób:

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

(To rozwiązanie zostało dodane przeze mnie jako komentarz na tej stronie. Po zdobyciu 19 głosów za tym komentarzem, postanowiłem dodać To rozwiązanie jako formalną odpowiedź na korzyść społeczności!)

 2
Author: Gal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-15 08:21:44

Rozmiar zależy od zawartości załadowanej wewnątrz i opcji przycinania. Jeśli jest to textview, to zależy również od zawijania, ile wierszy tekstu, rozmiaru czcionki, i tak dalej i dalej. Prawie niemożliwe dla Ciebie obliczenie siebie. Dobrą wiadomością jest to, że jest on obliczany po załadowaniu widoku i w viewWillAppear. Wcześniej wszystko jest nieznane, a rozmiar zawartości będzie taki sam jak rozmiar klatki. Ale w metodzie viewWillAppear i po (np. viewdidappear) zawartość rozmiar będzie rzeczywisty.

 1
Author: PapaSmurf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-27 03:25:51

Owijając Kod Richy ' ego stworzyłem własną klasę UIScrollView, która automatyzuje zmiana rozmiaru treści całkowicie!

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

Jak używać:
Wystarczy zaimportować .plik h do kontrolera widoku i deklaruje wystąpienie sbscrollview zamiast zwykłego UIScrollView.

 1
Author: AmitP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-19 20:15:26

Ustaw dynamiczny Rozmiar zawartości w ten sposób.

 self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
 1
Author: Monika Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-16 08:03:23

To zależy od treści naprawdę: treść.rama.wzrost może dać ci to, czego chcesz ? Zależy, czy treść jest pojedynczą rzeczą, czy zbiorem rzeczy.

 0
Author: Andiih,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-31 15:12:46

Znalazłem też odpowiedź Lewiatana na najlepszą. Obliczał jednak dziwną wysokość. Jeśli przewijanie jest ustawione na wyświetlanie wskaźników przewijania podczas przewijania, będą one znajdować się w tablicy podglądów. W takim przypadku rozwiązaniem jest tymczasowe wyłączenie wskaźników przewijania przed zapętleniem, a następnie przywrócenie ich poprzedniego ustawienia widoczności.

-(void)adjustContentSizeToFit jest publiczną metodą na niestandardowej podklasie 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;
}
 0
Author: clayzar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-14 17:23:53

Myślę, że może to być zgrabny sposób aktualizacji rozmiaru widoku zawartości 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
    }
}
 0
Author: Furqan Khan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-12 11:50:44

Dlaczego nie jedna linijka kodu??

_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);
 0
Author: Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-29 08:12:21

Dla swift4 z redukcją:

self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
   return $0.union($1.frame)
}).size
 0
Author: mm282,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-22 12:26:48