2012-11-08 12 views
12

Sto provando a impostare un UIView nella parte inferiore del contenuto di un UIScrollView, faccio così a impostare la posizione della vista sull'altezza contensize della scrollview. Ma la mia scrollview è una sottoview di un UIWebView così quando le immagini vengono caricate, l'altezza del contenuto cambia e la mia vista che dovrebbe essere nella parte inferiore della scrollview finisce nel mezzo ...rileva le modifiche al contenuto della vista di scorrimento di UIWebView Dimensione

Quindi sto cercando un modo essere avvisati quando il contenuto della pagina di scroll cambia. Ho cercato di sottoclasse e cambiare il setter per contensize per inviare un NSNotification:

@implementation UIScrollView (Height) 

-(void)setContentSize:(CGSize)contentSize 
{ 
    _contentSize=contentSize; 
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"scrollViewContentSizeChanged" object:nil]]; 
} 

@end 

Ma compilazione ottengo ed errore che dice:

"_OBJC_IVAR _ $ _ UIScrollView._contentSize", si fa riferimento da : - [UIScrollView (Altezza) setContentSize:] in MyClass.o ld: il simbolo (s) non trovato per l'architettura ARMv7

Qualsiasi idea di come il setter dovrebbe essere una sottoclasse?

Grazie!

risposta

28

Forse è possibile utilizzare l'osservazione dei valori-chiave (KVO) per rilevare le modifiche alle dimensioni del contenuto. Non ho provato, ma il codice dovrebbe essere simile a questo:

static int kObservingContentSizeChangesContext; 

- (void)startObservingContentSizeChangesInWebView:(UIWebView *)webView { 
    [webView.scrollView addObserver:self forKeyPath:@"contentSize" options:0 context:&kObservingContentSizeChangesContext]; 
} 

- (void)stopObservingContentSizeChangesInWebView:(UIWebView *)webView { 
    [webView.scrollView removeObserver:self forKeyPath:@"contentSize" context:&kObservingContentSizeChangesContext]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if (context == &kObservingContentSizeChangesContext) { 
     UIScrollView *scrollView = object; 
     NSLog(@"%@ contentSize changed to %@", scrollView, NSStringFromCGSize(scrollView.contentSize)); 
    } else { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 

Se questo non funziona, potrebbe essere necessario Swizzle il metodo setContentSize:. Il metodo swizzling consente al metodo di sostituzione di chiamare il metodo originale, che è ciò che è necessario fare per passare la nuova dimensione del contenuto alla vista di scorrimento.

Si può leggere di più sul metodo swizzling qui: http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html

Penso che questo è il codice più importante per swizzling: https://github.com/rentzsch/jrswizzle

+0

grazie per aver segnalato il mio errore. cancellata la risposta :) –

+1

KVO funziona come un incantesimo, grazie mille! – Abel

+0

@rob mayoff puoi condividere, questo su swift3? –

3

Il tuo approccio è la metà corretta. È sicuramente possibile sovrascrivere un metodo esistente attraverso una categoria, ciò che non si può fare, sebbene acceda a un ivar della classe.

In questo caso, quello che ti serve è il metodo swizzling: hai la precedenza su setContentSize e allo stesso tempo tieni un riferimento all'implementazione originale del metodo, quindi puoi chiamarlo per impostare il valore _contentSize.

Qui è il codice che si potrebbe usare, con i commenti:

@implementation UIScrollView (Height) 

// -- this method is a generic swizzling workhorse 
// -- it will swap one method impl with another and keep the old one 
// under your own impl name 
+ (void)swizzleMethod:(SEL)originalSel andMethod:(SEL)swizzledSel { 

    Method original = class_getInstanceMethod(self, originalSel); 
    Method swizzled = class_getInstanceMethod(self, swizzledSel); 
    if (original && swizzled) 
    method_exchangeImplementations(original, swizzled); 
    else 
    NSLog(@"Swizzling Fault: methods not found."); 

}  

//-- this is called on the very moment when the categoty is loaded 
//-- and it will ensure the swizzling is done; as you see, I am swapping 
//-- setContentSize and setContentSizeSwizzled; 
+ (void)load { 
    [self swizzleMethod:@selector(setContentSize:) andMethod:@selector(setContentSizeSwizzled:)]; 
} 

//-- this is my setContentSizeSwizzled implementation; 
//-- I can still call the original implementation of the method 
//-- which will be avaiable (*after swizzling*) as setContentSizeSwizzled 
//-- this is a bit counterintuitive, but correct! 
- (void)setContentSizeSwizzled:(CGSize)contentSize 
{ 
    [self setContentSizeSwizzled:contentSize]; 
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"scrollViewContentSizeChanged" object:nil]]; 
} 

@end 

Speranza che aiuta.

+0

Grazie mille per questa bella risposta. Ma ho una domanda. Se ho più istanze per l'oggetto, come posso rilevare quale istanza sta chiamando questo metodo? –

+0

@ OlcayErtaş: potresti usare 'postNotificationName: object: userInfo:' e inviare 'self' come' userInfo' o qualsiasi altra informazione utile: https://developer.apple.com/reference/foundation/nsnotificationcenter/1410608-postnotificationname? language = objc – sergio

+0

Ho fatto lo stesso. Grazie per la risposta. –

Problemi correlati