Czy istnieje sposób na UIScrollView
automatyczne dostosowanie wysokości (lub szerokości) przewijanej treści?
Coś jak:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
Czy istnieje sposób na UIScrollView
automatyczne dostosowanie wysokości (lub szerokości) przewijanej treści?
Coś jak:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
Najlepsza metoda, z jaką kiedykolwiek się spotkałem, aby zaktualizować rozmiar treści na UIScrollView
podstawie zawartych w nim podglądów podrzędnych:
Cel C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
Szybki
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size
viewDidLayoutSubviews
więc automatyczne układanie się zakończyło, w iOS7 działało dobrze, ale testowanie systemu operacyjnego iOS6 z jakiegoś powodu nie zakończyło pracy, więc miałem złe wartości wysokości, więc przełączyłem się naviewDidAppear
teraz działa dobrze. żeby tylko wskazać, że może ktoś by tego potrzebował. dziękiUIScrollView nie zna automatycznie wysokości swojej zawartości. Musisz sam obliczyć wysokość i szerokość
Zrób to z czymś w rodzaju
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 pod drugim. Jeśli masz widok obok siebie, wystarczy dodać wysokość jednego, jeśli nie chcesz ustawiać zawartości przewijacza na większą niż jest w rzeczywistości.
źródło
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
Rozwiązanie, jeśli używasz układu automatycznego:
Ustaw
translatesAutoresizingMaskIntoConstraints
sięNO
na wszystkich widokach zaangażowanych.Ustaw i zmień rozmiar widoku przewijania z ograniczeniami zewnętrznymi w stosunku do widoku przewijania.
Użyj ograniczeń, aby rozłożyć podglądy w widoku przewijania, upewniając się, że ograniczenia wiążą się 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
źródło
Dodałem to do odpowiedzi Espuza i JCC. Używa pozycji y widoków podrzędnych i nie obejmuje pasków przewijania. Edytuj Używa dolnej części najniższego widocznego widoku podrzędnego.
+ (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; }
źródło
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
na początku iself.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
na końcu metody?Oto szybko akceptowana odpowiedź dla każdego, kto jest zbyt leniwy, aby ją przekonwertować :)
var contentRect = CGRectZero for view in self.scrollView.subviews { contentRect = CGRectUnion(contentRect, view.frame) } self.scrollView.contentSize = contentRect.size
źródło
Oto adaptacja odpowiedzi @ leviatan w języku Swift 3:
ROZBUDOWA
import UIKit extension UIScrollView { func resizeScrollViewContentSize() { var contentRect = CGRect.zero for view in self.subviews { contentRect = contentRect.union(view.frame) } self.contentSize = contentRect.size } }
STOSOWANIE
Bardzo łatwy w użyciu!
źródło
Poniższe 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.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 } }
Logika jest taka sama z podanymi odpowiedziami. Jednak pomija ukryte widoki,
UIScrollView
a obliczenia są wykonywane po ustawieniu wskaźników przewijania jako ukrytych.Istnieje również opcjonalny parametr funkcji i możesz dodać wartość przesunięcia, przekazując parametr do funkcji.
źródło
Świetne i najlepsze rozwiązanie od @leviathan. Po prostu przekłada się na szybkość przy użyciu podejścia FP (programowanie funkcjonalne).
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), { CGRectUnion($0, $1.frame) }.size
źródło
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($1.frame) }).size
Możesz uzyskać wysokość zawartości wewnątrz UIScrollView, obliczając, które dziecko „sięga dalej”. Aby to obliczyć, należy wziąć pod uwagę początek Y (początek) i wysokość przedmiotu.
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))];
Robiąc to w ten sposób, elementy (podglądy) nie muszą być układane bezpośrednio jeden pod drugim.
źródło
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)];
Zasadniczo ustalamy, który element jest najbardziej wysunięty w dół w widoku i dodajemy wypełnienie 10 pikseli na dole
źródło
Ponieważ scrollView może mieć inne scrollViews lub inne drzewo subViews inDepth, preferowane jest rekurencyjne uruchamianie dogłębne.
Szybki 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) } }
Stosowanie
źródło
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 uzyskaniu 19 głosów pozytywnych na ten komentarz, zdecydowałem się dodać to rozwiązanie jako formalną odpowiedź dla dobra społeczności!)
źródło
Dla swift4 przy użyciu redukuj:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, { return $0.union($1.frame) }).size
źródło
Rozmiar zależy od zawartości załadowanej do niego i opcji przycinania. Jeśli jest to widok tekstu, zależy to również od zawijania, liczby wierszy tekstu, rozmiaru czcionki itd. I tak dalej. Prawie niemożliwe do obliczenia siebie. Dobrą wiadomością jest to, że jest obliczany po załadowaniu widoku i w pliku viewWillAppear. Wcześniej wszystko jest nieznane, a rozmiar zawartości będzie taki sam jak rozmiar ramki. Ale w metodzie viewWillAppear i po (na przykład viewDidAppear) rozmiar zawartości będzie rzeczywisty.
źródło
Zawijanie kodu Richy'ego Stworzyłem niestandardową klasę UIScrollView, która całkowicie automatyzuje zmianę rozmiaru treści!
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ć:
Po prostu zaimportuj plik .h do kontrolera widoku i zadeklaruj instancję SBScrollView zamiast zwykłej instancji UIScrollView.
źródło
tak naprawdę zależy od treści: content.frame.height może dać ci to, czego chcesz? Zależy, czy treść jest pojedynczą rzeczą, czy zbiorem rzeczy.
źródło
Uważam również, że odpowiedź Lewiatana działa najlepiej. Jednak obliczał dziwną wysokość. Jeśli w pętli podglądów podrzędnych ustawiono wyświetlanie wskaźników przewijania, będą one znajdować się w tablicy widoków podrzędnych. 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 metodą publiczną w 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; }
źródło
Myślę, że może to być zgrabny sposób aktualizowania 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 } }
źródło
dlaczego nie pojedyncza linia kodu?
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);
źródło
Ustaw dynamiczny rozmiar treści w ten sposób.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
źródło
import UIKit class DynamicSizeScrollView: UIScrollView { var maxHeight: CGFloat = UIScreen.main.bounds.size.height var maxWidth: CGFloat = UIScreen.main.bounds.size.width override func layoutSubviews() { super.layoutSubviews() if !__CGSizeEqualToSize(bounds.size,self.intrinsicContentSize){ self.invalidateIntrinsicContentSize() } } override var intrinsicContentSize: CGSize { let height = min(contentSize.height, maxHeight) let width = min(contentSize.height, maxWidth) return CGSize(width: width, height: height) } }
źródło