16

我试图在 UIScrollView 的内容底部设置一个 UIView,这样做我将视图的位置设置为滚动视图的 contentsize 高度。但是我的滚动视图是 UIWebView 的子视图,因此当加载图像时,内容大小的高度会发生变化,而我应该位于滚动视图底部的视图最终会出现在中间......

所以我正在寻找一种在滚动视图的内容大小发生变化时得到通知的方法。我尝试将其子类化并更改 contentsize 的设置器以发送 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:] in MyClass.old:未找到架构 armv7 的符号

知道 setter 应该如何被子类化吗?

谢谢 !

4

2 回答 2

32

也许您可以使用键值观察 (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:方法。方法调配让您的替换方法调用原始方法,这是您将新内容大小传递给滚动视图所需要做的事情。

您可以在此处阅读有关方法调配的更多信息:http: //www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html

我认为这是最流行的调酒代码:https ://github.com/rentzsch/jrswizzle

于 2012-11-08T19:04:56.770 回答
3

你的方法对了一半。您当然可以通过类别覆盖现有方法,但您不能做的是访问该类的 ivar。

在这种情况下,您需要的是方法调配:您在覆盖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

希望能帮助到你。

于 2012-11-08T19:12:23.063 回答