有没有办法得到一个通知,回调或其他方式来调用一个方法,每当一个UIView变得可见的用户,即当一个UIScrollview是一些UIViews的超级视图,并且这样一个UIView的ViewController应该得到当用户看到它的视图时通知它?如何在UIView变得可见时得到通知?
我知道的可能,但检查不那么优雅的解决了滚动滚动哪个位置(通过UIScrollViewDelegate的方法)和计算,如果子视图中的任何一个可见...
但我正在寻找以更普遍的方式来做到这一点。
有没有办法得到一个通知,回调或其他方式来调用一个方法,每当一个UIView变得可见的用户,即当一个UIScrollview是一些UIViews的超级视图,并且这样一个UIView的ViewController应该得到当用户看到它的视图时通知它?如何在UIView变得可见时得到通知?
我知道的可能,但检查不那么优雅的解决了滚动滚动哪个位置(通过UIScrollViewDelegate的方法)和计算,如果子视图中的任何一个可见...
但我正在寻找以更普遍的方式来做到这一点。
如果您的视图呈现行为,它应该位于视图控制器内。在视图控制器上,每次出现视图时都会调用viewDidAppear方法。
- (void)viewDidAppear:(BOOL)animated
viewDidAppear的问题在于,它仅在使用导航控制器时被调用。在我的情况下,视图从屏幕上滚动*滚动,然后滚动回来。滚动似乎不触发viewDidAppear .... – 2010-03-19 11:19:56
那么,什么可以表明视图是否出现在屏幕上与滚动? – 2014-05-21 08:01:12
“它应该在视图控制器内。” - 并且视图控制器仅适用于全屏视图。有时候我们只能看到屏幕的一部分。 – Jonny 2016-02-09 06:29:28
视图的图层属性应该告诉我们,如果这种观点是可见或不可见
[view.layer visibleRect];
但心不是为我工作。
因此,解决方法是使用UiScrollView contentOffset属性来计算特定的视图是否可见。
那么如何添加一个触发器,当该值发生变化时触发? – 2015-08-07 14:55:26
很久以前我就回答了这个问题,即使我忘记了上下文。 子类UIView并使用以下方法。 https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/doc/uid/TP40006816-CH3-SW139 – 2015-08-10 11:31:36
这就是我现在正在做的。我想听一门外部课程。 – 2015-08-17 19:43:45
我不认为有一种通用的方式来做到这一点的意见。听起来像你被困在scrollViewDidEndScrolling和其他ScrollViewDelegate方法。但我不确定为什么你说它很优雅,它们很简单。
我已经设法解决这个问题是这样的:
首先,添加一个类别的UIView以下方法:
// retrieve an array containing all super views
-(NSArray *)getAllSuperviews
{
NSMutableArray *superviews = [[NSMutableArray alloc] init];
if(self.superview == nil) return nil;
[superviews addObject:self.superview];
[superviews addObjectsFromArray:[self.superview getAllSuperviews]];
return superviews;
}
然后,在你看来,检查窗口属性设置:
-(void)didMoveToWindow
{
if(self.window != nil)
[self observeSuperviewsOnOffsetChange];
else
[self removeAsSuperviewObserver];
}
如果它被设置,我们会观察每个上海华盈的“contentOffset”上的任何变化。如果窗口是零,我们将停止观察。您可以将的keyPath更改为任何其他财产,也许“帧”如果在你的superviews没有的UIScrollView:
-(void)observeSuperviewsOnOffsetChange
{
NSArray *superviews = [self getAllSuperviews];
for (UIView *superview in superviews)
{
if([superview respondsToSelector:@selector(contentOffset)])
[superview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
}
-(void)removeAsSuperviewObserver
{
NSArray *superviews = [self getAllSuperviews];
for (UIView *superview in superviews)
{
@try
{
[superview removeObserver:self forKeyPath:@"contentOffset"];
}
@catch(id exception) { }
}
}
现在实行“observeValueForKeyPath” - 方法:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:@"contentOffset"])
{
[self checkIfFrameIsVisible];
}
}
最后,检查是否视图的框架在窗口框架内可见:
-(void)checkIfFrameIsVisible
{
CGRect myFrameToWindow = [self.window convertRect:self.frame fromView:self];
if(myFrameToWindow.size.width == 0 || myFrameToWindow.size.height == 0) return;
if(CGRectContainsRect(self.window.frame, myFrameToWindow))
{
// We are visible, do stuff now
}
}
感谢您的详细解决方案。我尝试了一下,但问题是在我有机会移除观察者之前,超级视图正在被释放。我甚至观察他们的“超级观点”关键路径的变化,但它没有帮助。这绝对是KVO最糟糕的部分。 – phatmann 2015-08-27 18:13:58
这应该是没有问题的,我猜。如果superview被释放,观察视图(我们想知道它的视图是否可见)也应该被释放,因为它是子视图。 – Thomas 2015-08-27 22:20:52
你说得对。我的问题是我没有在所有关键路径上调用removeObserver。也就是说,KVO最佳实践是保留所有观察对象的所有权。在这种情况下,这意味着将由'observeSuperviewsOnOffsetChange'创建的超级视图列表放入成员变量中,并在'removeAsSuperviewObserver'中使用此保留的超级列表列表。这也有轻微的性能优势。 – phatmann 2015-08-28 19:16:33
我的应用程序的导航基于水平滚动UIScrollView。我也通过分类的UIWindow拦截触摸。因此,当前可见视图的ViewController需要将自己注册为委托给子类UIWindow。这就是我希望在视图变得可见时得到通知的原因。 – 2010-03-17 21:09:52