如何从 UICollectionViewCell 访问 UICollectionView 中 Cell 的 indexPath

Posted

技术标签:

【中文标题】如何从 UICollectionViewCell 访问 UICollectionView 中 Cell 的 indexPath【英文标题】:how to access from UICollectionViewCell the indexPath of the Cell in UICollectionView 【发布时间】:2012-12-14 08:59:23 【问题描述】:

我想在调用动作时为 UICollectionViewCell 设置动画。 我在Interface Builder 中完成了UICollectionViewCell,也完成了UICollectionView。 现在我想在我的actionBtnAddToCard 方法中获得正确的indexPath

这就是我现在尝试的方式(ProduktViewCell.m 中的方法):

- (IBAction)actionAddToCart:(id)sender 
    XLog(@"");

    // see this line
    NSIndexPath *indexPath = ??** how can i access the correct indexPath**??;
    SortimentViewController *svc = [[SortimentViewController alloc] initWithNibName:@"SortimentViewController_iPad" bundle:[NSBundle mainBundle]];
    [svc.collectionViewProdukte cellForItemAtIndexPath:indexPath];

    [svc collectionView:svc.collectionViewProdukte didSelectItemAtIndexPath:indexPath];
 

SortimentViewController 是继承 UICollectionView 的 viewController。如何访问正确的 indexPath?

更新 1:编辑帖子以便更好地理解。

【问题讨论】:

看看这个 SO 答案,这是一种更优雅和简单的方式***.com/questions/13966291/… 【参考方案1】:
- (IBAction)actionAddToCart:(id)sender 
   NSIndexPath *indexPath;
   indexPath = [self.collectionView indexPathForItemAtPoint:[self.collectionView convertPoint:sender.center fromView:sender.superview]]; 
   ...

【讨论】:

【参考方案2】:

如果您知道视图层次结构,这很容易。

UIButton *button = (UiButton *) sender;

如果按钮是这样的-> UITableViewCell->按钮

那么你可以得到这样的单元格

UITableViewCell *cell = (UITableViewCell *)[button superview];

如果按钮是这样的-> UITableViewCell -> 内容视图-> 按钮

UITableViewCell *cell = (UITableViewCell *)[[button superview] superview];

最后可以像这样提取索引路径

NSIndexPath *indexPath = [self.table_View indexPathForCell:cell];

【讨论】:

是的,在集合视图的上下文中谈论你的意思时有点困惑,你介意向我们展示一个完整的动作 sn-p 吗? OP 已经要求在 UICollectionView 而不是 UITableViewCell 的情况下提供解决方案。恕我直言,这个答案向读者发送了错误信息。请编辑指出如何在 UICollectionView 中执行此操作。 [[button superview] superview] 很脆弱。我在下面添加了一个更安全的答案。 UITableViewCell *cell = (UITableViewCell *)[[button superview] superview];帮帮我。当我有:button->collectionview->UItableviewcell 很抱歉,但多次调用 superview 非常麻烦。对视图层次结构的更改很容易中断此类调用。而这个原始问题不涉及 UITableView。【参考方案3】:

不依赖于视图。 试试这个。

CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:buttonPosition];

NSLog(@"%ld", (long)indexPath.row);

【讨论】:

【参考方案4】:

使用像[[button superview] superview] 这样的代码是脆弱的,而且不是面向未来的;实际上,除非您明确测试它,否则它甚至不能保证适用于所有 ios 版本。为此,我总是使用迭代辅助方法:-

- (UIView *)superviewWithClassName:(NSString *)className fromView:(UIView *)view

    while (view)
    
        if ([NSStringFromClass([view class]) isEqualToString:className])
        
            return view;
        
        view = view.superview;
    
    return nil;

然后我从按钮处理程序中调用它,如下所示:-

- (IBAction)buttonClicked:(id)sender

    UIButton *button = (UIButton *)sender;
    UICollectionViewCell *cell = (UICollectionViewCell *)
                                [self superviewWithClassName:@"UICollectionViewCell"
                                fromView:button];
    if (cell)
    
        NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
        // do whatever action you need with the indexPath...
    

更新:superviewWithClassName 的 Swift 版本。使它成为一个类方法,因为它从不引用self

static func superviewWithClassName(className:String, fromView view:UIView?) -> UIView? 
    guard let classType = NSClassFromString(className) else 
        return nil
    
    var v:UIView? = view
    while (v != nil) 
        if v!.isKindOfClass(classType) 
            return v
        
        v = v!.superview
    
    return nil

以及一些调用它的代码,来自prepareForSegue 或按钮处理程序:-

guard let cell = UIView.superviewWithClassName("UICollectionViewCell", fromView: sender as? UIView) as? UITableViewCell else return

【讨论】:

【参考方案5】:

Swift 解决方案: 像这样的 UICollectionView 扩展对此很有用。

extension UICollectionView 
    func indexPathForView(view: AnyObject) -> NSIndexPath? 
        let originInCollectioView = self.convertPoint(CGPointZero, fromView: (view as! UIView))
        return self.indexPathForItemAtPoint(originInCollectioView)
    

在任何地方都可以轻松使用。

let indexPath = collectionView.indexPathForView(button)

【讨论】:

很好的解决方案。谢谢【参考方案6】:

您可以这样做,indexPathsForVisibleItems 将为当前在视图中可见的项目返回 NSIndexPaths 数组,第一个对象返回第一个(如果每个视图有一个单元格)。

NSIndexPath *indexPath = [[svc.collectionViewProdukte indexPathsForVisibleItems] firstObject]

【讨论】:

考虑添加解释【参考方案7】:

如果要为特定单元格设置动画,则需要获取对该单元格的引用。只需调用

[svc.collectionViewProdukte cellForItemAtIndexPath:indexPath];

什么都不做。您需要保留该方法返回的单元格,如下所示:

UICollectionViewCell *cell = [svc.collectionViewProdukte cellForItemAtIndexPath:indexPath];

之后,继续制作动画:

[UIView animateWithDuration:0.2f animations:^
    cell.transform = CGAffineTransformMakeScale(0.5f, 0.5f);
];

【讨论】:

但是我怎样才能得到 indexPath?我会更新我的问题以便更好地理解 indexPath 只是引用特定单元格的一种方式。在不知道您的应用做什么的情况下,我无法猜测您要为哪个单元格设置动画。 要获取第一个单元格,应该是这样的: NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; 那是我的问题。如何找出调用了哪些单元格操作? 这真的取决于你的应用程序的结构。如果每个单元格都有一个“添加到购物车”按钮,您可能会考虑将该按钮放在单元格内(应该是 UICollectionViewCell 子类),并确保按钮调用单元格本身(而不是视图控制器)上的方法.然后使用委托模式在视图控制器上调用一些逻辑方法:类似于 -(void)addToCartButtonPressedForCell:(UICollectionViewCell *)cell];【参考方案8】:

Swift 3 解决方案:基于 Ishan Handa 的回答

extension UICollectionView 
func indexPathForView(view: AnyObject) -> IndexPath? 
    let originInCollectioView = self.convert(CGPoint.zero, from: (view as! UIView))
    return self.indexPathForItem(at: originInCollectioView) as IndexPath?
  

用法:

func deleteCell(sender:UIButton)
    var indexPath:IndexPath? = nil
    indexPath = self.collectionView.indexPathForView(view: sender)        
    print("index path : \(indexPath)")

【讨论】:

【参考方案9】:
//Note: this is for a storyboard implementation

// here is code for finding the row and section of a textfield being edited in a uicollectionview
UIView *contentView = (UIView *)[textField superview];
UICollectionViewCell *cell = (UICollectionViewCell *)[contentView superview];
cell = (UICollectionViewCell *)[contentView superview];

// determine indexpath for a specific cell in a uicollectionview
NSIndexPath *editPath = [myCollectionView indexPathForCell:cell];
int rowIndex = editPath.row;
int secIndex = editPath.section;

【讨论】:

【参考方案10】:

尽管我在这里找到了很多答案。这将是最短且有用的,与视图层次结构无关

- (void) actionAddToCart:(id)sender

    id view = [sender superview];

    while (view && [view isKindOfClass:[UICollectionViewCell class]] == NO) 
    
        view = [view superview];
    
    NSIndexPath *thisIndexPath = [self.collectionView indexPathForCell:view];

    NSLog(@"%d actionAddToCart pressed",thisIndexPath.row);

【讨论】:

【参考方案11】:

您几乎可以肯定有一个 UICollectionViewCell 子类。只需添加一个属性并在 cellForItemAtIndexPath 中设置 indexPath。

【讨论】:

这一直有效,直到您启用对项目的重新排序,然后您必须手动进入并修复所有受影响单元格的 indexPath 属性。【参考方案12】:

Xcode10。 Swift 4.2 版本。

extension UICollectionView 

  func indexPathForView(view: AnyObject) -> IndexPath? 
      guard let view = view as? UIView else  return nil 
      let senderIndexPath = self.convert(CGPoint.zero, from: view)
      return self.indexPathForItem(at: senderIndexPath)
  


用法:

// yourView can be button for example
let indexPath = collectionView.indexPathForView(view: yourView) 

【讨论】:

【参考方案13】:
 internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: “cell_id”, for: indexPath)
    
    let bttn_obj = UIButton(frame: CGRect(x: 5.5, y: 5.5, width: 22, height: 22))
    bttn_obj.addTarget(self, action: #selector(bttn_action), for: UIControl.Event.touchUpInside)
    cell.addSubview(bttn_obj)        
    
    return cell


@IBAction func bttn_action(_ sender: UIButton) -> Void 
    
    let cell_view = sender.superview as! UICollectionViewCell
    let index_p : IndexPath = self.collectionview.indexPath(for: cell_view)!
    
    print(index_p)
 

【讨论】:

以上是关于如何从 UICollectionViewCell 访问 UICollectionView 中 Cell 的 indexPath的主要内容,如果未能解决你的问题,请参考以下文章

如何从自定义 UICollectionViewCell 启动 View Controller

如何从 UICollectionViewCell 访问 UICollectionView 中 Cell 的 indexPath

如何从不同的方法访问 UICollectionViewCell 中标签的文本?

如何从 UICollectionViewController 验证 UICollectionViewCell 的值

从 UICollectionViewCell 中点击按钮时,如何引用 UITableViewCell?

如何从特定的 UICollectionViewCell 中删除 firebase 子节点 - Swift