2010-10-25 13 views
18

Un UIView ha un metodo SizeToFit che renderà UIView adatto a tutte le sue sotto-visualizzazioni. C'è qualcosa di simile, che restituirà solo la dimensione che calcola e non modifica il frame di una vista.SizeToFit su una dimensione del contenuto di UIScrollView

Ho diverse visualizzazioni secondarie su un UIScrollView e voglio fare SizeToFit sul contenuto della vista di scorrimento di ContentSize, piuttosto che sul suo frame. Devo farlo su contentSize, perché non voglio aumentare la dimensione "reale" di UIScrollView e il contenuto viene caricato dinamicamente e in modo asincrono, quindi non posso farlo manualmente quando aggiungo le subviews a UIScrollView .

+0

Iniziare una taglia su questo. Al momento, la risposta migliore che ho è quella di scorrere le sottoview e guardare i loro frame. Mi chiedo se c'è un modo migliore. SizeThatFits: non sembra aiutare. –

+0

Prova a sovrascrivere sizeThatFits: per eseguire il calcolo desiderato. – titaniumdecoy

+0

[estensione Swift] (http://stackoverflow.com/a/36504526/1634890) –

risposta

38

Al momento, questa è la migliore che ho:

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

Questo metodo è grande, ma ... per qualche ragione, non funziona per me se il telefono è in modalità orizzontale. Qualche idea? – Reuven

+0

Questa soluzione non tiene conto delle UIImageViews che sono già presenti come sottoview di UIScrollView se le barre di scorrimento sono impostate per essere visualizzate (vedere [questo post SO] (http://stackoverflow.com/questions/5664281/uiscrollview-phantom-subviews)). Un modo per filtrare questi fuori potrebbe essere quella di impostare la proprietà tag dei subviews l'utente vuole includere nel calcolo del ciclo per lo stesso valore diverso da zero, e utilizzare un'istruzione if per filtrare. –

+1

@adamjansch Oppure usa 'isKindOfClass:' al posto di 'tag's. Oppure usa: '[self.subviews filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @" class =% @ ", [UILabel class]]];' - errato perché usa 'class' e non' isKindOfClass: ', ma abbastanza buono per la maggior parte utilizza. –

0

Inserire un UIView in UIScrollView che abbia la stessa larghezza e altezza e aggiungere tutti i subviews all'IT anziché alla scrollview. Quindi imposta la proprietà clipToBounds sulla scrollview su TRUE e chiama sizeToFit sul tuo UIView. Puoi anche impostare l'opacità dello sfondo di UIView su 0 rendendolo invisibile, ma mostrando comunque le sue sottoview.

+0

ho capito che dovrebbe essere il contrario: La vista racchiude dovrebbe essere UIView, mentre l'interno (più grande) visualizzazione dovrebbe essere il trasparente UIScrollView. Quindi dovrebbe funzionare. – thgc

+0

Sei sicuro, quello che hai scritto nella sua risposta ha un senso, ho avuto anche se quello che hai detto qui, ma sembra un po ' "improprio" –

+0

Ci scusiamo per il ritardo di reazione ... ho parzialmente utilizzato la soluzione di cui sopra per il mio progetto al lavoro la settimana scorsa. Sfortunatamente, sizeToFit non sembra avere alcun effetto su UIScrollView all'interno di UIView. Così ho impostato manualmente il suo contentSize dopo aver aggiunto tutti i subviews ad esso. In questo modo non è più necessario nemmeno l'UIView di chiusura. – thgc

4

Se la funzione viene chiamata spesso, non vorrete per scorrere i subviews ogni volta. Invece, ogni volta che viene aggiunta una sottoview, crea un'unione di contentSize corrente e il frame della nuova sottoview.

- (void)didAddSubview:(UIView *)subview { 
    CGRect tmp; 
    tmp.origin = CGPointZero; 
    tmp.size = self.contentSize; 
    tmp = CGRectUnion(tmp,subview.frame); 
    self.contentSize = tmp.size; 
} 
+0

Probabilmente una buona soluzione in alcune situazioni. Sfortunatamente, le mie sottoview sono spesso ridimensionate. Quindi nel mio caso, questa non è una buona soluzione. –

+0

@WilliamJockusch Se le sottoview vengono ridimensionate di frequente, è possibile aggiungere un osservatore KVO per 'frame' o' bounds' e aggiornare 'contentSize' di conseguenza. Sarebbe complicato, ma a seconda del numero di sottoview potrebbe valerne la pena. –

2

trovato una soluzione qui ScrollView ContentSize, si sarà in grado di trovare le dimensioni delle subviews e trovare la dimensione dei contenuti combinato e anche le opzioni di dire se subviews sono disposti orizzontalmente o verticalmente.

ecco il codice dal link qui sopra:

@interface UIScrollView(auto_size) 
- (void) adjustHeightForCurrentSubviews: (int) verticalPadding; 
- (void) adjustWidthForCurrentSubviews: (int) horizontalPadding; 
- (void) adjustWidth: (bool) changeWidth andHeight: (bool) changeHeight withHorizontalPadding: (int) horizontalPadding andVerticalPadding: (int) verticalPadding; 
@end 

@implementation UIScrollView(auto_size) 
- (void) adjustWidth: (bool) changeWidth andHeight: (bool) changeHeight withHorizontalPadding: (int) horizontalPadding andVerticalPadding: (int) verticalPadding { 
    float contentWidth = horizontalPadding; 
    float contentHeight = verticalPadding; 
    for (UIView* subview in self.subviews) { 
     [subview sizeToFit]; 
     contentWidth += subview.frame.size.width; 
     contentHeight += subview.frame.size.height; 
    } 

    contentWidth = changeWidth ? contentWidth : self.superview.frame.size.width; 
    contentHeight = changeHeight ? contentHeight : self.superview.frame.size.height; 

    NSLog(@"Adjusting ScrollView size to %fx%f, verticalPadding=%d, horizontalPadding=%d", contentWidth, contentHeight, verticalPadding, horizontalPadding); 
    self.contentSize = CGSizeMake(contentWidth, contentHeight); 
} 

- (void) adjustHeightForCurrentSubviews: (int) verticalPadding { 
    [self adjustWidth:NO andHeight:YES withHorizontalPadding:0 andVerticalPadding:verticalPadding]; 
} 

- (void) adjustWidthForCurrentSubviews: (int) horizontalPadding { 
    [self adjustWidth:YES andHeight:NO withHorizontalPadding:horizontalPadding andVerticalPadding:0]; 
} 
@end 

assicurarsi di avere uno sguardo ai commenti sulla pagina blog come è fornita una soluzione alternativa anche.

-anoop

1

Ho fatto una funzione per impostare la dimensione del contenuto di ScrollView provare e godere

Prima di tutto scrivere questa funzione ...

-(void)setContentSizeOfScrollView:(UIScrollView*)scroll 
{ 
    CGRect rect = CGRectZero; 

    for(UIView * vv in [scroll subviews]) 
    { 
     rect = CGRectUnion(rect, vv.frame); 
    } 

    [scroll setContentSize:CGSizeMake(rect.size.width, rect.size.height)]; 
} 

poi dopo l'aggiunta di tutti gli elementi basta chiamare questa funzione e passare la visualizzazione scroll come argomento .....

[self setContentSizeOfScrollView:self.YourScrollView]; 

Sono sicuro al 100% che funzionerà .........

0

a Swift 2.1, aggiungere questo al vostro controller della vista:

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    let aggregateView = contentView.subviews.reduce(CGRect()) 
     { aggRect, view in aggRect.union(view.frame) } 

    scrollView.contentSize = aggregateView.size 

} 
-1

Swift 2 estensione:

Uso:

scrollView.contentResize
scrollView.contentWidthResize
scrollView.contentHeightResize

extension UIScrollView { 

    ///Will resize content size to fit all subviews. 
    func contentResize(){ 

     var w = CGFloat(0) 
     var h = CGFloat(0) 

     for view in self.subviews{ 

      let fw = view.frame.origin.x + view.frame.width 
      let fh = view.frame.origin.y + view.frame.height 

      w = max(fw, w) 
      h = max(fh, h) 

     } 

     contentSize = CGSize(width: w, height: h) 

    } 

    ///Will resize content width size to fit all subviews. 
    func contentWidthResize(){ 

     var w = CGFloat(0) 

     for view in self.subviews{ 

      let fw = view.frame.origin.x + view.frame.width 

      w = max(fw, w) 

     } 

     contentSize.width = w 

    } 

    ///Will resize content height size to fit all subviews. 
    func contentHeightResize(){ 

     var h = CGFloat(0) 

     for view in self.subviews{ 

      let fh = view.frame.origin.y + view.frame.height 

      h = max(fh, h) 

     } 

     contentSize.height = h 

    } 

} 
+1

'view.w' e' view.h' non sono definiti accoppiamenti. –

+0

@YoussefSami modificato ..., per favore considera di rimuovere il downvote e votando se lo trovi utile, grazie per le informazioni. –

1

Questa è la risposta per Swift 3.0

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    var contentRect: CGRect = CGRect.zero 
    for view in self.scrollView.subviews { 
     debugPrint("view frame \(view.frame)") 
     contentRect = contentRect.union(view.frame) 
     debugPrint("frame \(contentRect)") 
    } 
    self.scrollView.contentSize = contentRect.size 
    debugPrint("content size \(self.scrollView.contentSize)") 
} 
1

Mentre William's answer è stato molto utile, non ha funzionato alla perfezione in quanto le barre di scorrimento sono anche subviews del ScrollView. Risulta, il trucco è quello di nasconderli prima di calcolare la dimensione del contenuto. Ecco ciò che il codice Swift 3 sarà simile:

override func viewDidLayoutSubviews() { 
    scrollView.layoutSubviews() 

    // disable scrollbars so they don't interfere during resizing 
    scrollView.showsVerticalScrollIndicator = false 
    scrollView.showsHorizontalScrollIndicator = false 

    scrollView.contentSize = scrollView.subViewArea() 

    // re-enable the scrollbars 
    scrollView.showsVerticalScrollIndicator = true 
    scrollView.showsHorizontalScrollIndicator = true 
} 

Avrete anche bisogno di aggiungere la seguente estensione qualche parte nel progetto:

extension UIScrollView { 
    func subViewArea() -> CGSize { 
     var rect = CGRect.zero 
     for subview in subviews { 
      rect = rect.union(subview.frame) 
     } 

     return rect.size 
    } 
} 
0

Non basta che le dimensioni del telaio unione per calcolare il contenuto dimensione. Perché a volte la sottoview deve sovrapporsi e talvolta i margini tra le sottoview. Devi conoscere e calcolare l'origine delle sottoview.

approccio dell'Unione dà stessa altezza di contenuti per i disegni A e B. Ma se si sa più grande ultima visualizzazione secondaria, è possibile calcolare a destra altezza contenuti:

enter image description here

Questa estensione può calcolare l'altezza reale contenuto.

extension UIScrollView { 

func adjustContentHeight(bottomPadding: Int = 0) { 

    var lastSub: CGRect = .zero 
    self.subviews.forEach({ 
     let sub = $0.frame 
     if(sub.maxY > lastSub.maxY) { 
      lastSub = sub 
     } 
    }) 

    self.contentSize.height = lastSub.maxY + CGFloat(bottomPadding) 
} 
} 
Problemi correlati