ios - controllo - come sbloccare lo schermo dell ipad



UICollectionViewFlowLayout Dimensioni Avviso quando si ruota il dispositivo in orizzontale (14)

Stiamo utilizzando UICollectionView per visualizzare la cella che copre l'intero schermo (meno lo stato e la barra di navigazione). La dimensione della cella è impostata da self.collectionView.bounds.size :

- (void)viewWillAppear:(BOOL)animated
{
    //
    // value isn't correct with the top bars until here
    //
    CGSize tmpSize = self.collectionView.bounds.size;
    _currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
}

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    return _currentCellSize;
}

Questo imposta il corretto dimensionamento per ciascun dispositivo. Ogni cella è definita per non avere margini e il layout non ha intestazione o piè di pagina. Tuttavia, quando ruotiamo da verticale a orizzontale otteniamo il seguente "reclamo":

the behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less that the height of the UICollectionView minus the section insets top and bottom values.

Ora capisco questo errore, tuttavia ripristiniamo la dimensione della cella e utilizziamo i layout di flusso integrati nella transizione di rotazione:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    //self.collectionView.bounds are still the last size...not the new size here
}
- (void)didRotateFromInterfaceOrientation: UIInterfaceOrientation)fromInterfaceOrientation
{
    CGSize tmpSize = self.collectionView.bounds.size;
    _currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
    [self.collectionView performBatchUpdates:nil completion:nil];//this will force the redraw/size of the cells.
}

Le celle vengono visualizzate correttamente nel paesaggio.

Sembra che Flow Layout veda la vecchia dimensione della cella (che causa il reclamo dal momento che sarà troppo alta), ma legge / rende la nuova dimensione della cella impostata in didRotateFromInterfaceOrientation .

C'è un modo per sbarazzarsi della denuncia?

Abbiamo provato a trovare un altro gancio durante una transizione di rotazione del dispositivo che ha accesso alla dimensione dello schermo di destinazione corretta (rispetto alla dimensione dello schermo corrente) senza fortuna. L'output di debug mostra che il willRotateToInterfaceOrientation si verifica dopo willRotateToInterfaceOrientation ma prima didRotateFromInterfaceOrientation .

Abbiamo anche verificato l'ovvio; se impostiamo l'altezza della cella a una dimensione fissa inferiore all'altezza dello schermo orizzontale, il reclamo non si verifica. Inoltre, il reclamo non si verifica quando si ruota da orizzontale a verticale.

Tutto funziona correttamente e rende correttamente. Tuttavia questa lamentela ci preoccupa. Qualcun altro ha qualche idea o soluzione?

https://ffff65535.com


È possibile UICollectionView sottoclassi UICollectionView e sovrascrivere setBounds: Lì prima di chiamare [super setBounds:] la dimensione dell'articolo può essere adattata ai nuovi limiti.
È necessario verificare se la dimensione dei limiti è stata modificata, poiché setBounds: viene richiamato anche durante lo scorrimento.


Cercando di trovare una soluzione per mettere a tacere questi avvertimenti su iOS 7 si stava rivelando difficile per me. Ho finito per ricorrere alla sottoclasse del mio UICollectionView e UICollectionView aggiunto il seguente codice.

- (void)setFrame:(CGRect)frame
{
    if (!iOS8 && (frame.size.width != self.frame.size.width))
    {
        [self.collectionViewLayout invalidateLayout];
    }

    [super setFrame:frame];
}

Alcuni potrebbero voler eseguire un controllo di intera dimensione con CGSizeEqualToSize() .


Ho appena incontrato e risolto lo stesso problema. Dal momento che la mia soluzione è più simile a quella che stavi chiedendo e non corrisponde a nessuna risposta esistente, l'ho pubblicata qui.

#define NUMBER_OF_CELLS_PER_ROW 1

- (UICollectionViewFlowLayout *)flowLayout {
    return (UICollectionViewFlowLayout *)self.collectionViewLayout;
}

- (CGSize)itemSizeInCurrentOrientation {
    CGFloat windowWidth = self.collectionView.window.bounds.size.width;

    CGFloat width = (windowWidth - (self.flowLayout.minimumInteritemSpacing * (NUMBER_OF_CELLS_PER_ROW - 1)) - self.flowLayout.sectionInset.left - self.flowLayout.sectionInset.right)/NUMBER_OF_CELLS_PER_ROW;

    CGFloat height = 80.0f;

   return CGSizeMake(width, height);
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.flowLayout invalidateLayout];
    self.flowLayout.itemSize = [self itemSizeInCurrentOrientation];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    // Now that the rotation is complete, load the cells.
    [self.collectionView reloadData];
}

Ho incontrato lo stesso problema durante il ridimensionamento del frame di un UICollectionView. Se ho usato il metodo delegate su FlowLayout per restituire la dimensione della cella (che verrebbe aggiornata in base alle dimensioni del UICollectionView), ricevo il messaggio di errore quando ridimensiono (più piccolo) il frame di UICollectionView, poiché non sembra chiedere al delegato informazioni aggiornate sulle dimensioni prima di lamentarsi. Alla fine avrebbe chiesto il metodo delegato per informazioni sulle dimensioni durante il ridisegno, ma emetterebbe comunque l'avviso nel momento in cui ho assegnato un nuovo metodo di frame. Per eliminare l'avviso, imposto esplicitamente la proprietà itemSize dell'oggetto UICollectionViewFlowLayout prima di impostare il frame su un nuovo valore più piccolo. La mia situazione è abbastanza semplice che penso di poter fare a meno di eseguire il calcolo itemSize a questo punto (poiché tutti i miei elementi nella vista della raccolta hanno la stessa dimensione), invece di dipendere dal metodo delegato. Solo impostando la proprietà itemSize lasciando il metodo delegate implementato non è stato risolto il problema, poiché penso che abbia ignorato il valore di itemSize se ha rilevato che il metodo delegate è stato implementato (se sa che è lì, perché non lo chiama ?!). Speriamo che questo aiuti - forse è anche possibile impostare in modo esplicito itemSize prima della rotazione.


Ho usato un UICollectionViewFlowLayoutInvalidationContext , in cui calcolo il nuovo offset in modo tale che mantenga lo stesso offset di contenuto. My own collectionViewSizeForOrientation: restituisce la dimensione corretta. Non è perfetto, ma almeno non è impreciso:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    CGSize fromCollectionViewSize = [self collectionViewSizeForOrientation:[self interfaceOrientation]];
    CGSize toCollectionViewSize = [self collectionViewSizeForOrientation:toInterfaceOrientation];

    CGFloat currentPage = [_collectionView contentOffset].x / [_collectionView bounds].size.width;
    NSInteger itemCount = [_collectionView numberOfItemsInSection:0];

    UICollectionViewFlowLayoutInvalidationContext *invalidationContext = [[UICollectionViewFlowLayoutInvalidationContext alloc] init];

    [invalidationContext setContentSizeAdjustment:CGSizeMake(toCollectionViewSize.width * itemCount - fromCollectionViewSize.width * itemCount, toCollectionViewSize.height - fromCollectionViewSize.height)];
    [invalidationContext setContentOffsetAdjustment:CGPointMake(currentPage * toCollectionViewSize.width - [_collectionView contentOffset].x, 0)];

    [[_collectionView collectionViewLayout] invalidateLayoutWithContext:invalidationContext];

    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

collectionViewSizeForOrientation: nel mio caso è il seguente, supponendo che insets e spaziatura articolo siano 0:

- (CGSize)collectionViewSizeForOrientation:(UIInterfaceOrientation)orientation
{
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;

    CGFloat width = UIInterfaceOrientationIsLandscape(orientation) ? MAX(screenSize.width, screenSize.height) : MIN(screenSize.width, screenSize.height);
    CGFloat height = UIInterfaceOrientationIsLandscape(orientation) ? MIN(screenSize.width, screenSize.height) : MAX(screenSize.width, screenSize.height);

    return CGSizeMake(width, height);

}


Il seguente codice lo ha risolto per me:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.collectionView.frame.size;
}

La mia correzione era semplice come la deselezione di "Adjust Scroll View Insets" per il controller di visualizzazione in IB, poiché avevo bisogno che la barra di navigazione fosse traslucida.


Molte soluzioni suggeriscono di aggiungere invalidateLayout a willAnimateRotationToInterfaceOrientation - ma questo è deprecato da iOS 8.

Per iOS 8 e versioni successive, utilizzare:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    [self.collectionView.collectionViewLayout invalidateLayout];
}

Grazie al commento di @ user7097242, ecco una versione swift4:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    self.collectionView.collectionViewLayout.invalidateLayout()
}

Non gettare un altro gambero su questa barbie carica, ma non accettata.

- (CGSize)collectionView:(UICollectionView *)collectionView 
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    [collectionView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
    return CGSizeMake(100, collectionView.frame.size.height);
}

L'impostazione degli insiemi di contenuti appena prima di restituire la dimensione della cella ha fatto il trucco per me.

Nota:

Sto usando una vista container in uno storyboard per caricare la vista insieme in un UIViewController. Ho provato a impostarlo sull'oggetto flowLayout nello storyboard. La vista dell'insieme nello storyboard. E sovrascrivendo uno dei UICollectionViewDelegateFlowLayout; anche se non ricordo quale. Non sono nemmeno sicuro se questo funzionerà per un layout verticale.


Nota: nel mio caso, ho scoperto che stavamo impostando la proprietà preferredContentSize di UIViewController in questione. Se ritieni che questo sia il tuo caso, potresti dover gestire il seguente metodo del protocollo UICollectionViewDelegateFlowLayout :

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGSize size = collectionViewLayout.collectionView.bounds.size;
    ...
    return size;
}

Questo funziona per me: (e spero che funzioni anche per te!)

- (void)viewWillLayoutSubviews 
{     
     self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height);    
     [self.flowLayout invalidateLayout];
}

- (void)viewDidLayoutSubviews     
{
    self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height); 
}

Questo l'ha risolto per me:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

E sto usando questo metodo delegato per impostare la dimensione:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

E posso da lì usare questo con il frame corretto dopo la rotazione:

self.collectionView.frame.size

Solo per sopprimere l'avvertimento e (probabilmente, non sono sicuro) migliorare le prestazioni che si potrebbero ottenere prima di restituire la dimensione

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

controllare se il controller della vista è in fase di rotazione e se è di ritorno alcune dimensioni relativamente piccole come CGSizeMake(0.1, 0.1)


Stavo ricevendo lo stesso avvertimento. Insoddisfatto dell'approccio "reloadData", ho scoperto che chiamare [self.collectionView.collectionViewFlowLayout invalidateLayout] prima di impostare il frame della vista di raccolta ha messo a tacere l'avviso e ha prodotto i risultati previsti.





uicollectionviewlayout