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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14737183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:10:24  来源:igfitidea点击:

Getting the screen location of a cell from a UICollectionView

iosuicollectionviewuicollectionviewcell

提问by Joe Jupin

This isn't so much a question as an explanation of how to solve this problem.

这与其说是一个问题,不如说是解释如何解决这个问题。

The first thing to realize is that the UICollectionViewdoes inherit from a UIScrollView- so doing a standard lookup with a scroll view's content is the best solution.

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

Here's the problem I was addressing:

这是我要解决的问题:

I had a UICollectionViewthat had differing items in each cell - along with differing types of cells. I need the selection of a cell to cause an effect of the image in the cell to appear to expand and take over the whole screen. How I did the expansion is for another post.

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

The challenge was getting the cell's position on the screen so that the animating section would have a reference point from where to start.

挑战在于获取单元格在屏幕上的位置,以便动画部分有一个从哪里开始的参考点。

So, to facilitate getting this information - consider the following code:

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

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

Hopefully, this helps other folks that are trying to figure out how to say overlay something on the cell in an exact position, etc...

希望这可以帮助其他人试图弄清楚如何在单元格上的确切位置叠加某些东西,等等......

回答by Alivin

-(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);
}

It work for me.You can try yourself

它对我有用。你可以自己试试

回答by elio.d

Well the first part of your question is pretty much clear, the second one?? anyway if what you want to get is the frame of the select cell in your collection you can use this :

那么你的问题的第一部分非常清楚,第二部分??无论如何,如果你想得到的是你的集合中选择单元格的框架,你可以使用这个:

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

More info here

更多信息在这里

回答by OhadM

@Alivin solution using layoutAttributesForItemAtIndexPathworks but only for the presented/current scroll view that the user sees.

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

Meaning, if you select the firstpresented visible cells you will get the actual frame, butif you scroll, the framewill have a deviation and you won't get the coordinates you need.

意思是,如果您选择第一个显示的可见单元格,您将获得实际的frame但是如果您滚动,frame将会有偏差并且您将无法获得所需的坐标。

This is why you need to use convertPoint:toView:

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

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

Basically this method takes a point (cell.center) in one view and convert that point to another view (collectionView.superview) coordinate system which is exactly what we need.

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

Thus, realCenterwill always contain the coordinates to the actual selected cell.

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

回答by Farhan Patel

I've done this before as well. it took a while but it is possible.

我以前也这样做过。这花了一段时间,但这是可能的。

You need to use

你需要使用

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

Where currentImageView is the image that the user taps. It's superview will be the cell. You want to convert the rect of your image to where it actually is on a different view. That view is called "translateView" here.

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

So what is translateView? In most cases it is just self.view.

那么什么是翻译视图?在大多数情况下,它只是self.view.

This will give you a new frame for your imageview that will meet where your image is on your table. Once you have that you can expand the image to take up the entire screen.

这将为您的图像视图提供一个新框架,该框架将与您的图像在桌面上的位置相交。完成后,您可以扩展图像以占据整个屏幕。

Here is a gist of the code I use to tap an image then expand the image and display a new controller that allows panning of the image.

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

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

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

回答by mdb983

An alternative is to use the events to provide most if not all the answers to your questions.

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

I presume that a touch event will initiate all of this, so lets implement something meaningful;

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

  //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 ... before you rush off for happy hour, lets not forget to read up on;

哦......在你匆匆忙忙地度过欢乐时光之前,让我们不要忘记阅读;

   <UICollectionViewDelegate> (hint - it's needed)  

回答by Lance Samaria

I needed to know the exact location of the cell's center that a user tapped relative to the UIWindow. In my situation the collectionView was a child of a view that took up 2/3 of the screen and its superview was a child of another view. Long story short using the collectionView.superView wasn't suffice and I needed the window. I used Ohadman's answer aboveand this answer from TomerButo get the tapped location of the screen/window's coordinate system.

我需要知道用户点击的单元格中心相对于 UIWindow 的确切位置。在我的情况下,collectionView 是占据屏幕 2/3 的视图的子视图,它的超级视图是另一个视图的子视图。长话短说,使用 collectionView.superView 是不够的,我需要窗口。我使用了上面的 Ohadman 答案TomerBu 的这个答案来获取屏幕/窗口坐标系的点击位置。

Assuming your app has 1 window that it isn't connected across multiple screens, I used both of these and the same exact location printed out.

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

It's important to know that this is going to give you the exact middle of the cell (relative to the window). Even if you touch the top, left, bottom or right side of the cell it's going to return the coordinate of the center of the cell itself and not the exact location that you tapped.

重要的是要知道这将为您提供单元格的确切中间(相对于窗口)。即使您触摸单元格的顶部、左侧、底部或右侧,它也会返回单元格本身中心的坐标,而不是您点击的确切位置。

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

    guard let cell = collectionView.cellForItem(at: indexPath) as? YourCell else { return }
    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)")
}