UICollectionView - resizing cells on device rotate - Swift

后端 未结 9 1551
醉梦人生
醉梦人生 2020-12-04 23:12

I\'ve created a UICollectionView, so that I can arrange views into neat columns. I\'d like there to be a single column on devices > 500 pixels wide.

In order to achi

相关标签:
9条回答
  • 2020-12-04 23:50

    Perhaps the most straight way to make this is to invalidateLayout during the viewWillTransitionToSize:

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
            return
        }
        flowLayout.invalidateLayout()
    }
    
    0 讨论(0)
  • 2020-12-04 23:56

    You can create a mask content and move it to the collectionView. After the landscape/portrait animation is finished, you must remove it ASAP.

    Here is an example:

    @property (strong, nonatomic) UIImageView *maskImage;
    
    .........
    
    - (UIImageView *) imageForCellAtIndex: (NSInteger) index {
        UICollectionView *collectionView = self.pagerView.test;
        FSPagerViewCell *cell = nil;
        NSArray *indexPaths = [collectionView indexPathsForVisibleItems];
        for (NSIndexPath *indexPath in indexPaths) {
            if (indexPath.item == index) {
                cell = (FSPagerViewCell *)[collectionView cellForItemAtIndexPath: indexPath];
                break;
            }
        }
        if (cell) {
            return cell.imageView;
        }
        return nil;
    }
    
    
    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
    
    {
        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
        [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
         {
             UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
             [self test_didRotateFromInterfaceOrientation: orientation];
    
             UIImageView *imageView = [self imageForCellAtIndex: self.pagerView.currentIndex];
             if (imageView) {
                     UIImageView *imageView = [self imageForCellAtIndex: self.pagerView.currentIndex];
                     CGSize itemSize = self.pagerView.itemSize;
                     UIImageView *newImage = [[UIImageView alloc] initWithImage: imageView.image];
                     [newImage setFrame: CGRectMake((_contentView.bounds.size.width - itemSize.width)/2.0f, 0, itemSize.width, itemSize.height)];
                     newImage.contentMode = imageView.contentMode;
                     newImage.clipsToBounds = imageView.clipsToBounds;
                     newImage.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
                     [self.pagerView addSubview: newImage];
    
                     self.maskImage = newImage;
             }
    
             [self.pagerView.test performBatchUpdates:^{
                 [self.pagerView.test setCollectionViewLayout:self.pagerView.test.collectionViewLayout animated:YES];
             } completion:nil];
             // do whatever
         } completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
         {
             [self.maskImage removeFromSuperview];
         }];
    }
    
    0 讨论(0)
  • 2020-12-04 23:59

    To have the collection view resize its cells, and have the change animated during rotation, use the transition coordinator:

    (Swift 4+)

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
    
        // Have the collection view re-layout its cells.
        coordinator.animate(
            alongsideTransition: { _ in self.collectionView.collectionViewLayout.invalidateLayout() },
            completion: { _ in }
        )
    }
    
    0 讨论(0)
  • 2020-12-05 00:01

    I had a task to adjust items size in UICollectionView subclass. The best method for this is setFrame. Property collectionViewFlowLayout I passed from ViewController (in my case it was outlet from default flow layout).

    // .h
    @property (nonatomic, weak) UICollectionViewFlowLayout *collectionViewFlowLayout;
    
    // .m
    - (void)setFrame:(CGRect)frame {
        if (!CGSizeEqualToSize(frame.size, self.frame.size)) {
            collectionViewFlowLayout.itemSize =
            CGSizeMake((UIDeviceOrientationIsLandscape(UIDevice.currentDevice.orientation) ? (frame.size.width - 10) / 2 : frame.size.width), collectionViewFlowLayout.itemSize.height);
        }
        [super setFrame:frame];
    }
    
    0 讨论(0)
  • 2020-12-05 00:04

    You might use viewWillLayoutSubviews. This question should be helpful but this is bassically called whenever the view controller views is about to layout its subviews.

    So your code will look like this:

    override func viewWillLayoutSubviews() {
      super.viewWillLayoutSubviews()
    
      guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
        return
      }
    
      if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
        //here you can do the logic for the cell size if phone is in landscape
      } else {
        //logic if not landscape 
      }
    
      flowLayout.invalidateLayout()
    }
    
    0 讨论(0)
  • 2020-12-05 00:07

    I've tended to use viewWillTransitionToSize with the same thing and simply made a call invalidateLayout() in there.

    0 讨论(0)
提交回复
热议问题