Keeping the contentOffset in a UICollectionView while rotating Interface Orientation

后端 未结 24 1351
野性不改
野性不改 2020-12-04 07:22

I\'m trying to handle interface orientation changes in a UICollectionViewController. What I\'m trying to achieve is, that I want to have the same contentOffset afte

相关标签:
24条回答
  • 2020-12-04 08:04

    I had the issue with my project,i used two different layout for the UICollectionView.

    mCustomCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"LandScapeCell" forIndexPath:indexPath];
    
    theCustomCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"PortraitCell" forIndexPath:indexPath];
    

    Then Check it for each orientation and use your configuration for each orientation.

    0 讨论(0)
  • 2020-12-04 08:07

    I think the correct solution is to override targetContentOffsetForProposedContentOffset: method in a subclassed UICollectionViewFlowLayout

    From the docs:

    During layout updates, or when transitioning between layouts, the collection view calls this method to give you the opportunity to change the proposed content offset to use at the end of the animation. You might override this method if the animations or transition might cause items to be positioned in a way that is not optimal for your design.

    0 讨论(0)
  • 2020-12-04 08:07

    Use <CollectionViewDelegateFlowLayout> and in the method didRotateFromInterfaceOrientation: reload data of the CollectionView.

    Implement collectionView:layout:sizeForItemAtIndexPath: method of <CollectionViewDelegateFlowLayout> and in the method verify the Interface orientation and apply your custom size of each cell.

    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
    {
    
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    
        if (UIInterfaceOrientationIsPortrait(orientation)) {
    
            return CGSizeMake(CGFloat width, CGFloat height);
    
        } else {
    
            return CGSizeMake(CGFloat width, CGFloat height);
    
        }
    
    }
    
    0 讨论(0)
  • 2020-12-04 08:07

    The "just snap" answer is the right approach and doesn't require extra smoothing with snapshot overlays IMO. However there's an issue which explains why some people see that the correct page isn't scrolled to in some cases. When calculating the page, you'd want to use the height and not the width. Why? Because the view geometry has already rotated by the time targetContentOffsetForProposedContentOffset is called, and so what was the width is now the height. Also rounding is more sensible than ceiling. So:

    - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
    {
        NSInteger page = round(proposedContentOffset.x / self.collectionView.bounds.size.height);
        return CGPointMake(page * self.collectionView.bounds.size.width, 0);
    }
    
    0 讨论(0)
  • 2020-12-04 08:07

    I had got some troubles with animateAlongsideTransition block in animateAlongsideTransition (see the code below).

    Pay attention, that it is called during (but not before) the animation My task was update the table view scroll position using scrolling to the top visible row (I’ve faced with the problem on iPad when table view cells shifted up when the device rotation, therefore I was founding the solution for that problem). But may be it would be useful for contentOffset too.

    I tried to solve the problem by the following way:

    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
        __weak TVChannelsListTableViewController *weakSelf = self;
    
        [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            weakSelf.topVisibleRowIndexPath = [[weakSelf.tableView indexPathsForVisibleRows] firstObject];
        } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            [weakSelf.tableView scrollToRowAtIndexPath:weakSelf.topVisibleRowIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
        }];
    }
    

    But it didn’t work. For instance, index path of the top cel was (0, 20). But when the device rotation animateAlongsideTransition block was called and [[weakSelf.tableView indexPathsForVisibleRows] firstObject] returned index path (0, 27).

    I thought the problem was in retrieving index paths to weakSelf. Therefore to solve the problem I’ve moved self.topVisibleRowIndexPath before [coordinator animateAlongsideTransition: completion] method calling:

    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
        __weak TVChannelsListTableViewController *weakSelf = self;
        self.topVisibleRowIndexPath = [[weakSelf.tableView indexPathsForVisibleRows] firstObject];
    
        [coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            [weakSelf.tableView scrollToRowAtIndexPath:weakSelf.topVisibleRowIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
        }];
    }
    

    And the other interesting thing that I’ve discovered is that the deprecated methods willRotateToInterfaceOrientation and willRotateToInterfaceOrientation are still successful called in iOS later 8.0 when method viewWillTransitionToSize is not redefined.

    So the other way to solve the problem in my case was to use deprecated method instead of new one. I think it would be not right solution, but it is possible to try if other ways don’t work :)

    0 讨论(0)
  • 2020-12-04 08:07

    You might want to try this untested code:

    - (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) toInterfaceOrientation
                                     duration: (NSTimeInterval)         duration
    {
        [UIView animateWithDuration: duration
                          animation: ^(void)
         {
           CGPoint newContentOffset = CGPointMake(self.scrollPositionBeforeRotation.x *
                                                  self.collectionView.contentSize.height,
                                                  self.scrollPositionBeforeRotation.y *
                                                  self.collectionView.contentSize.width);
           [self.collectionView setContentOffset: newContentOffset
                                        animated: YES];
         }];
    }
    
    0 讨论(0)
提交回复
热议问题