Подтвердить что ты не робот

ContentOffset не обновляется в UICollectionView, если scrollToItemAtIndexPath вызывается внутри viewWillAppear

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

Контроллер календаря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 не находится в окне, которое вы не можете прокручивать. Планирование прокрутки для следующего цикла цикла гарантирует, что представление было добавлено в окно и может быть правильно прокручено.

Испытывал ли кто-нибудь еще этот вопрос и каковы его обходные пути?

4b9b3361

Ответ 1

Если вы используете автоматический макет, проблема может заключаться в том, что ограничения еще не установили рамки. Попробуйте вызвать метод 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 content offset, if its subviews are added dynamically (in code)

        self.isFirstTimeViewDidLayoutSubviews = NO;
    }

Ответ 2

вы всегда можете форматировать макет.

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

Ответ 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 я сохраняю collectionView contentOffset в currentOffset. Таким образом, если я перейду к контроллеру, у которого есть коллекцияView, и я уже туда добрался, у меня всегда будет последняя позиция.

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

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

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

Ответ 4

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

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

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