从UICollectionView获取单元格的屏幕位置

问题描述 投票:50回答:6

这不是一个如何解决此问题的解释。

首先要意识到的是UICollectionView确实继承自UIScrollView-因此,使用滚动视图的内容进行标准查找是最佳解决方案。

这是我要解决的问题:

我有一个UICollectionView,每个单元格中都有不同的项目-以及不同类型的单元格。我需要选择一个单元格,以使该单元格中的图像效果看起来扩大并占据整个屏幕。我如何进行扩展的是另一篇文章。

挑战是获取单元在屏幕上的位置,以便动画部分从那里开始具有参考点。

因此,为了便于获取此信息,请考虑以下代码:

第一注:

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...

希望这能帮助其他试图弄清楚该如何说出某些内容的人重叠在单元格上的确切位置,等等。

ios uicollectionview uicollectionviewcell
6个回答
75
投票
-(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);
}

对我有用。您可以尝试一下


41
投票

您的问题的第一部分很清楚,第二部分呢?无论如何如果要获取的是集合中选择单元格的框架,则可以使用此:

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

更多信息here


20
投票

使用layoutAttributesForItemAtIndexPath的@Alivin解决方案有效,但仅适用于用户看到的当前/当前滚动视图。

意思是,如果选择first显示的可见单元格,则将获得实际的framebut如果滚动,则frame将存在偏差,并且不会获得坐标您需要。

这就是为什么您需要使用convertPoint:toView

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

基本上,此方法在一个视图中获取一个点(cell.center),并将该点转换为我们所需要的另一视图(collectionView.superview)坐标系。

因此,realCenter将始终包含实际选定单元格的坐标。


8
投票

我之前也这样做过。花了一段时间,但有可能。

您需要使用

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

其中currentImageView是用户点击的图像。这将是单元格的超级视图。您想将图像的矩形转换为实际在其他视图上的位置。该视图在此处称为“ translateView”。

那么什么是translateView?在大多数情况下,它只是self.view

这将为您的imageview提供一个新框架,该框架将与您的图像在桌子上的位置相吻合。一旦有了,您就可以展开图像以占据整个屏幕。

这是我用来敲击图像然后展开图像并显示一个允许平移图像的新控制器的代码的要点。

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


1
投票

一种替代方法是使用事件来提供问题的大部分(如果不是全部)答案。

我假设触摸事件将启动所有这些,所以让我们实现一些有意义的事情;

  //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!!


  }
}

哦……在您赶快欢乐时光之前,请不要忘记继续阅读;

   <UICollectionViewDelegate> (hint - it's needed)  

0
投票

我需要知道用户轻按单元的确切位置。在我的情况下,collectionView是一个视图的子视图,该视图占据了屏幕的2/3,而其superview是另一个视图的子视图。长话短说,使用collectionView.superView是不够的,我需要一个窗口。我使用了Ohadman's answer above和此answer from TomerBu来获取屏幕坐标系的点击位置。

假设您的应用程序有1个没有跨多个场景连接的窗口,我使用了这两个窗口并打印了相同的确切位置。

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    guard let layoutAttributes = collectionView.layoutAttributesForItem(at: indexPath) else { return }
    guard let window = UIApplication.shared.keyWindow else { return }

    let touchedLocationInWindow = collectionView.convert(cell.center, to: window)
    print("OhadM's version: \(touchedLocationInWindow)")

    let cPoint = layoutAttributes.center
    let tappedLocationInWindow = collectionView.convert(cPoint, to: window)
    print("TomerBu's version: \(tappedLocationInWindow)")
}
© www.soinside.com 2019 - 2024. All rights reserved.