web-dev-qa-db-fra.com

Obtention de l'emplacement d'écran d'une cellule à partir d'un UICollectionView

Ce n'est pas tant une question qu'une explication de la façon de résoudre ce problème.

La première chose à réaliser est que le UICollectionView hérite d'un UIScrollView - donc faire une recherche standard avec le contenu d'une vue de défilement est la meilleure solution.

Voici le problème que j'abordais:

J'avais un UICollectionView qui avait des éléments différents dans chaque cellule - ainsi que différents types de cellules. J'ai besoin de la sélection d'une cellule pour que l'effet de l'image dans la cellule apparaisse pour s'étendre et occuper tout l'écran. Comment j'ai fait l'extension est pour un autre poste.

Le défi consistait à obtenir la position de la cellule sur l'écran afin que la section animée ait un point de référence à partir duquel commencer.

Donc, pour faciliter l'obtention de ces informations, considérez le code suivant:

Première note:

UICollectionView *picturesCollectionView;
DrawingCell cell; // -> instanceof UICollectionViewCell with custom items.

// first, get the list of cells that are visible on the screen - you must do this every time
// since the items can change...  This is a CRITICAL fact.  You do not go through the
// entire list of cells - only those the collectionView indicates are visible.  Note 
// there are some things to watch out for - the visibles array does not match the indexPath.item
// number - they are independent.  The latter is the item number overall the cells, while
// the visibles array may have only 2 entries - so there is NOT a 1-to-1 mapping - keep
// that in mind.

NSArray *visibles = [self.picturesCollectionView visibleCells];

// now, cycle through the times and find the one that matches some criteria.  In my
// case, check that the cell for the indexPath passed matches the cell's imageView...
// The indexPath was passed in for the method call - note that the indexPath will point
// to the number in your datasource for the particular item - this is crucial.

for (int i=0; i<visibles.count; i++) {
    DrawingCell *cell = (DrawingCell *)visibles[i];
    if (cell.imageView.image == (UIImage *)images[indexPath.item]) {

        // at this point, we've found the correct cell - now do the translation to determine
        // what is it's location on the current screen...  You do this by getting the contentOffset
        // from the collectionView subtracted from the cell's Origin - and adding in (in my case)
        // the frame offset for the position of the item I wish to animate (in my case the
        // imageView contained within my custom collection cell...

        CGFloat relativeX = cell.frame.Origin.x - self.picturesCollectionView.contentOffset.x + cell.imageView.frame.Origin.x;
        CGFloat relativeY = cell.frame.Origin.y - self.picturesCollectionView.contentOffset.y + cell.imageView.frame.Origin.y;

        // I now have the exact screen coordinates of the imageView - so since I need this
        // to perform animations, I save it off in a CGRect - in my case, I set the size
        // exactly to the size of the imageView - so say you were doing a Flicker display
        // where you wanted to grow a selected image, you get the coordinates of the image
        // in the cell and the size from the displayed image...

        UIImageView *image = cell.imageView;

        // selectedCell is a CGRect that's global for the sake of this code...

        selectedCell = cell.frame;
        selectedCell.Origin.x = relativeX;
        selectedCell.Origin.y = relativeY;
        selectedCell.size.width = cell.imageView.frame.size.width;
        selectedCell.size.height = cell.imageView.frame.size.height;
    }
}

// done.  I have my coordinates and the size of the imageView I wish to animate and grow...

Espérons que cela aide d'autres personnes qui essaient de comprendre comment dire superposer quelque chose sur la cellule dans une position exacte, etc.

47
Joe Jupin
-(void)collectionView:(UICollectionView *)cv didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
{

UICollectionViewLayoutAttributes *attributes = [cv layoutAttributesForItemAtIndexPath:indexPath];

CGRect cellRect = attributes.frame;

CGRect cellFrameInSuperview = [cv convertRect:cellRect toView:[cv superview]];

NSLog(@"%f",cellFrameInSuperview.Origin.x);
}

Cela fonctionne pour moi. Vous pouvez vous essayer

74
Alivin

Eh bien, la première partie de votre question est à peu près claire, la seconde ?? de toute façon si ce que vous voulez obtenir est le cadre de la cellule de sélection dans votre collection, vous pouvez utiliser ceci:

UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
CGRect cellRect = attributes.frame;

Plus d'infos ici

41
elio.d

La solution @Alivin utilisant layoutAttributesForItemAtIndexPath fonctionne mais uniquement pour la vue de défilement présentée/actuelle que l'utilisateur voit.

Autrement dit, si vous sélectionnez les cellules visibles en premier présentées, vous obtiendrez le frame réel, mais si vous faites défiler, le frame aura une déviation et vous n'obtiendrez pas les coordonnées dont vous avez besoin.

C'est pourquoi vous devez utiliser convertPoint: toView :

let realCenter = collectionView.convertPoint(cell.center, toView: collectionView.superview)

Fondamentalement, cette méthode prend un point (cell.center) dans une vue et convertit ce point en un autre système de coordonnées de vue (collectionView.superview) qui est exactement ce dont nous avons besoin.

Ainsi, realCenter contiendra toujours les coordonnées de la cellule sélectionnée réelle.

17
OhadM

Je l'ai déjà fait auparavant. cela a pris du temps mais c'est possible.

Vous devez utiliser

[currentImageView.superview convertRect:currentImageView.frame toView:translateView]

Où currentImageView est l'image sur laquelle l'utilisateur appuie. C'est superview sera la cellule. Vous souhaitez convertir le rect de votre image à l'endroit où il se trouve réellement sur une vue différente. Cette vue est appelée "translateView" ici.

Alors, qu'est-ce que translateView? Dans la plupart des cas, c'est juste self.view.

Cela vous donnera un nouveau cadre pour votre image qui correspondra à l'endroit où votre image est sur votre table. Une fois que vous l'avez, vous pouvez agrandir l'image pour occuper tout l'écran.

Voici un résumé du code que j'utilise pour appuyer sur une image, puis agrandir l'image et afficher un nouveau contrôleur qui permet le panoramique de l'image.

https://Gist.github.com/farhanpatel/4964372

7
Farhan Patel

Une alternative est d'utiliser les événements pour fournir la plupart sinon toutes les réponses à vos questions.

Je suppose qu'un événement tactile déclenchera tout cela, permet donc d'implémenter quelque chose de significatif;

  //First, trap the event in the collectionView controller with;

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{

   // lets ensure it's actually visible (yes we got here from a touch event so it must be... just more info)
   if ([self.collectionView.indexPathsForVisibleItems containsObject:indexPath]) {

     // get a ref to the UICollectionViewCell at indexPath
     UICollectionViewCell *cell =(UICollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];

     //finally get the rect for the cell
     CGRect cellRect = cell.frame


      // do your processing here... a ref to the cell will allow you to drill down to the image without the headache!!


  }
}

oh ... avant de vous précipiter pour l'happy hour, n'oublions pas de lire;

   <UICollectionViewDelegate> (hint - it's needed)  
1
mdb983