Обнаруживать изменения в contentSize представления прокрутки UIWebView

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

Поэтому я ищу способ получать уведомления, когда изменяется размер содержимого прокрутки. Я попытался разделить его на подклассы и изменить установщик для содержимого для отправки NSNotification:

@implementation UIScrollView (Height)

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

@end

Но при компиляции я получаю сообщение об ошибке:

"_OBJC_IVAR _ $ _ UIScrollView._contentSize", на который ссылаются из: -[UIScrollView(Heigth) setContentSize:] в MyClass.o ld: символ (ы) не найден для архитектуры armv7

Любая идея, как сеттер должен быть разделен на подклассы?

Спасибо!

2 ответа

Решение

Возможно, вы можете использовать наблюдение значения ключа (KVO), чтобы обнаружить изменения в размере контента. Я не пробовал, но код должен выглядеть так:

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

Если это не сработает, вам может понадобиться setContentSize: метод. Swizzling метода позволяет вашему методу замены вызывать оригинальный метод, что вам нужно сделать, чтобы передать новый размер контента в представление прокрутки.

Вы можете прочитать больше о методе Swizzling здесь: http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html

Я думаю, что это самый популярный код для Swizzling: https://github.com/rentzsch/jrswizzle

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

В этом случае вам нужен метод swizzling: вы переопределяете setContentSize в то же время сохраняя ссылку на оригинальную реализацию метода, так что вы можете вызвать его для установки _contentSize значение.

Вот код, который вы можете использовать с комментариями:

@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

Надеюсь, поможет.

Другие вопросы по тегам