UICollectionView-cambiar el tamaño de las celdas en el dispositivo rotar-Swift
rotation resize (6)
He tendido a usar viewWillTransitionToSize
con la misma cosa y simplemente hice una llamada a invalidateLayout()
allí.
Creé UICollectionView, para poder organizar vistas en columnas ordenadas. Me gustaría que haya una sola columna en dispositivos> 500 píxeles de ancho.
Para lograr esto, creé esta función:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let size = collectionView.frame.width
if (size > 500) {
return CGSize(width: (size/2) - 8, height: (size/2) - 8)
}
return CGSize(width: size, height: size)
}
Esto funciona como se esperaba en la primera carga, sin embargo, cuando giro el dispositivo, el cálculo no siempre vuelve a suceder y las vistas no siempre se vuelven a dibujar como se esperaba. Aquí está mi código para cuando se gira el dispositivo:
override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
collectionView.collectionViewLayout.invalidateLayout()
self.view.setNeedsDisplay()
}
Supongo que olvidé volver a dibujar algo, pero no estoy seguro de qué. ¡Cualquier idea es muy gratamente recibida!
Puede crear un contenido de máscara y moverlo a collectionView. Una vez finalizada la animación de paisaje / retrato, debe eliminarla lo antes posible.
Aquí hay un ejemplo:
@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];
}];
}
Puede usar viewWillLayoutSubviews
. Esta pregunta debería ser útil, pero esto se llama con poca frecuencia siempre que las vistas del controlador de vista estén a punto de diseñar sus subvistas.
Entonces su código se verá así:
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()
}
Quizás la forma más directa de hacer esto es invalidarLayout durante el 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()
}
Tuve la tarea de ajustar el tamaño de los elementos en la subclase UICollectionView. El mejor método para esto es setFrame. Property collectionViewFlowLayout Pasé de ViewController (en mi caso era salida del diseño de flujo predeterminado).
// .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];
}
traitCollectionDidChange
método traitCollectionDidChange
se puede usar en lugar de viewWillLayoutSubviews
:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection, traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass ||
traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass else {
return
}
if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass == .regular {
// iPad portrait and landscape
// do something here...
}
if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular {
// iPhone portrait
// do something here...
}
if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass = .compact {
// iPhone landscape
// do something here...
}
collectionView?.collectionViewLayout.invalidateLayout()
collectionView?.reloadData()
}