我有一个UICollectionView,用于模拟iOS 7中的新日历。此集合视图位于具有selectedDate属性的控制器内。每当设置selectedDate属性时,集合视图应滚动到集合视图中的日期。
日历控制器的viewWillAppear还确保所选日期可见,因为此控制器已缓存并重复使用。
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.calendarView scrollToDate:[self selectedDate] animated:NO];
}
问题是,第一次显示日历控制器时滚动不起作用。集合视图的contentOffset不会更新。
我目前的解决方法是使用
安排滚动在下一个运行循环中进行dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^(void)
{
// Scroll to the date.
});
看起来当UICollectionView不在窗口中时,您无法滚动。将滚动调度到下一个运行循环,确保视图已添加到窗口中并且可以正确滚动。
还有其他人遇到过这个问题以及他们的解决方法吗?
答案 0 :(得分:22)
如果您使用自动布局,问题可能是约束尚未设置帧。尝试在viewDidLayoutSubviews中调用scrollToDate:方法(不带dispatch_after)。
@interface CustomViewController ()
@property (nonatomic) BOOL isFirstTimeViewDidLayoutSubviews; // variable name could be re-factored
@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
@end
@implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.isFirstTimeViewDidLayoutSubviews = YES;
}
- (void)viewDidLayoutSubviews
{
// only after layoutSubviews executes for subviews, do constraints and frames agree (WWDC 2012 video "Best Practices for Mastering Auto Layout")
if (self.isFirstTimeViewDidLayoutSubviews) {
// execute geometry-related code...
// good place to set scroll view's content offset, if its subviews are added dynamically (in code)
self.isFirstTimeViewDidLayoutSubviews = NO;
}
答案 1 :(得分:18)
您可以随时强制自动布局布局。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.view.layoutIfNeeded()
self.collectionView.scrollToItemAtIndexPath......
}
答案 2 :(得分:3)
bilobatum 的回答是正确的! 我写这篇文章是因为我没有评论的声誉......:/
我在项目中尝试了 bilobatum 的答案,它完美无缺! 我的代码:
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
if (currentOffset.y != 999) {
[collectionView setContentOffset:currentOffset animated:NO];
}
}
currentOsset是CGPoint
初始化的x = 0和y = 999值(CGPoint currentOffset = {0,999};
)
在viewWillDisappear
方法中,我将currentView的contentOffset保存在currentOffset中。
这样,如果我导航到具有collectionView的控制器,我之前导航到那里,我将始终拥有最后的位置。
适合您的代码:
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
[self.calendarView scrollToDate:[self selectedDate] animated:NO];
}
谢谢你 bilobatum 的答案!
答案 3 :(得分:0)
使用-viewDidLayoutSubviews创建了一个无限循环,使解决方案过于复杂。
相反,我只是添加了一个小延迟,以便在滚动之前创建约束:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([self.scheduleDate isThisWeek]) [self.calendarLayout performSelector:@selector(scrollToCurrentTime) withObject:nil afterDelay:1];
}