简体   繁体   English

如何从UICollectionViewCell访问UICollectionView中Cell的indexPath

[英]how to access from UICollectionViewCell the indexPath of the Cell in UICollectionView

i want to animate the UICollectionViewCell when action is called. 我想在UICollectionViewCell操作时为UICollectionViewCell设置动画。
i have done UICollectionViewCell in Interface Builder , the UICollectionView also. 我已经做了UICollectionViewCellInterface BuilderUICollectionView也。 Now i want to get the correct indexPath at my actionBtnAddToCard method. 现在我想在actionBtnAddToCard方法中获取正确的indexPath

thats the way i try it now (method in ProduktViewCell.m): 这就是我现在尝试的方式(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 is the viewController which inherits the UICollectionView. SortimentViewController是viewController,它继承了UICollectionView。
how to acces the correct indexPath? 如何访问正确的indexPath?

UPDATE 1: edited post for better understanding. 更新1:编辑帖子以便更好地理解。

- (IBAction)actionAddToCart:(id)sender {
   NSIndexPath *indexPath;
   indexPath = [self.collectionView indexPathForItemAtPoint:[self.collectionView convertPoint:sender.center fromView:sender.superview]]; 
   ...
}

if you know the view hierarchy it is easy. 如果你知道视图层次结构很容易。

UIButton *button = (UiButton *) sender;

if the button is like this - > UITableViewCell - > button 如果按钮是这样的- > UITableViewCell - >按钮

then you can get cell like this 然后你可以像这样得到细胞

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

if the button is like this - > UITableViewCell - > content view -> button 如果按钮是这样的- > UITableViewCell - >内容视图 - >按钮

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

and finally index path can be extracted like this 最后可以像这样提取索引路径

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

Do Not Depend on view. 不依赖于视图。 Try this. 尝试这个。

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

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

Using code like [[button superview] superview] is fragile and not future-proof; 使用像[[button superview] superview]这样的代码是脆弱的,不能面向未来; indeed, it's not even guaranteed to work on all iOS versions unless you explicitly test it. 实际上,除非您明确测试它,否则它甚至不能保证在所有iOS版本上运行。 I always use an iterative helper method for this purpose:- 为此,我总是使用迭代辅助方法: -

- (UIView *)superviewWithClassName:(NSString *)className fromView:(UIView *)view
{
    while (view)
    {
        if ([NSStringFromClass([view class]) isEqualToString:className])
        {
            return view;
        }
        view = view.superview;
    }
    return nil;
}

Then I call it from the button handler like so:- 然后我从按钮处理程序中调用它,如下所示: -

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

UPDATE: Swift version of superviewWithClassName . 更新: superviewWithClassName Swift版本。 Made it a class method since it never references self . 使它成为一种类方法,因为它从不引用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
}

and some code to call it, either from prepareForSegue or a button handler:- 以及从prepareForSegue或按钮处理程序调用它的一些代码: -

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

Swift solution: A UICollectionView extension like this one can be useful for this. Swift解决方案:像这样的UICollectionView扩展可能对此有用。

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

Usage becomes easy everywhere. 到处使用变得容易。

let indexPath = collectionView.indexPathForView(button)

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

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

If you want to animate a specific cell, you need to get a reference to that cell. 如果要为特定单元格设置动画,则需要获取对该单元格的引用。 Simply calling 只是打电话

[svc.collectionViewProdukte cellForItemAtIndexPath:indexPath];

does nothing. 什么也没做。 You need to keep the cell that the method returns, like this: 您需要保留方法返回的单元格,如下所示:

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

After that, go ahead and animate: 之后,继续进行动画制作:

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

Swift 3 Solution : Based on Ishan Handa's Answer 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?
  }
}

Usage: 用法:

func deleteCell(sender:UIButton){
    var indexPath:IndexPath? = nil
    indexPath = self.collectionView.indexPathForView(view: sender)        
    print("index path : \(indexPath)")
}
//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;

Even though many answer i found here .this will be shortest and useful irrespective of the view hierarchy 尽管我在这里找到了许多答案。无论视图层次如何,这都是最短且有用的

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

You almost certainly have a UICollectionViewCell subclass. 你几乎肯定有一个UICollectionViewCell子类。 Just add a property and set the indexPath in cellForItemAtIndexPath. 只需添加一个属性并在cellForItemAtIndexPath中设置indexPath。

Xcode10. Xcode10。 Swift 4.2 version. 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)
  }

}

Usage: 用法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM