2013-10-01 4 views
22

У меня есть UICollectionView, который используется для имитации нового календаря в iOS 7. Этот вид коллекции находится внутри контроллера, который имеет свойство selectedDate. Всякий раз, когда свойство selectedDate установлено, представление коллекции должно прокручиваться до даты в представлении коллекции.contentOffset не обновлено в UICollectionView, если scrollToItemAtIndexPath вызывается внутри viewWillAppear

Вид контроллера календаряWillAppear также гарантирует, что выбранная дата видна, поскольку этот контроллер кэшируется и повторно используется.

-(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

У меня такая же проблема (по иронии судьбы, после создания аналогичного управления календарем). Мое решение до сих пор заключалось в том, чтобы оживить прокрутку во время 'viewDidAppear:' – enjayem

ответ

22

Если вы используете автомат, проблема может заключаться в том, что ограничения еще не установили рамки. Попробуйте вызвать метод scrollToDate: в viewDidLayoutSubviews (без отправки_после).

@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; 
    } 
+0

Это вызовет проблему, если пользователь прокрутил прочь от выбранной даты, а затем вызвал viewDidLayoutSubviews. Пользователь может находиться в процессе прокрутки, а затем внезапно прокручивается до выбранной даты. В теории вы могли бы отслеживать какой-то флаг, так что его вызывают только один раз, но это похоже на хак, а затем на исправление. –

+0

@ReidMain При использовании автоматической компоновки я часто устанавливаю флажки в своем собственном коде, чтобы выполнить код, связанный с геометрией, при загрузке контроллера в первый раз. Я согласен, что это не кажется идеальным; Я предпочел бы выполнить этот код в viewDidLoad, потому что он становится вызываемым только при загрузке контроллера. Тем не менее, при работе с автоматической компоновкой viewDidLoad слишком рано для выполнения кода, связанного с геометрией (на самом деле viewDidLoad часто бывает слишком ранним, даже если не используется автоматическая компоновка). Сообщите нам, если вы найдете лучшее решение. – bilobatum

+0

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

3

bilobatum «s ответ правильный! Я пишу это, потому что у меня нет репутации комментировать ...:/

Я попытался bilobatum «s ответ в моем проекте, и он работал отлично! Мой код:

-(void)viewDidLayoutSubviews{ 
    [super viewDidLayoutSubviews]; 
    if (currentOffset.y != 999) { 
     [collectionView setContentOffset:currentOffset animated:NO]; 
    } 
} 

currentOsset является CGPoint инициализируется с х = 0 и у = 999 значений (CGPoint currentOffset = {0,999};)

В методе viewWillDisappear я сохраняю contentOffset в CollectionView находится в currentOffset. Таким образом, если я перейду к контроллеру, у которого есть коллекцияView, и я уже туда добрался, у меня всегда будет последняя позиция.

код, который будет работать для вас:

-(void)viewDidLayoutSubviews{ 
    [super viewDidLayoutSubviews]; 
    [self.calendarView scrollToDate:[self selectedDate] animated:NO]; 
} 

Спасибо bilobatum за ответ!

+2

У вас возникнут проблемы, если viewDidLayoutSubviews вызывается при прокрутке вашего пользователя. Они могли бы прокрутиться от текущего смещения, а затем они внезапно прокрутились к нему. –

0

Использование -viewDidLayoutSubviews создало бесконечный цикл, который сделал решение слишком сложным.
Вместо этого я просто добавил небольшую задержку, чтобы ограничения создать перед прокруткой:

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    if ([self.scheduleDate isThisWeek]) [self.calendarLayout performSelector:@selector(scrollToCurrentTime) withObject:nil afterDelay:1]; 
} 
14

вы всегда можете заставить автоматическую раскладку на макет.

override func viewWillAppear(animated: Bool) { 
    super.viewWillAppear(animated) 
    self.view.layoutIfNeeded() 
    self.collectionView.scrollToItemAtIndexPath...... 
} 
+0

Это решило мою проблему. – huyleit

Смежные вопросы