【问题标题】:how to access from UICollectionViewCell the indexPath of the Cell in UICollectionView如何从 UICollectionViewCell 访问 UICollectionView 中 Cell 的 indexPath
【发布时间】: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:编辑帖子以便更好地理解。

【问题讨论】:

标签: ios ibaction uicollectionview nsindexpath uicollectionviewcell


【解决方案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)
                 
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-03-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多