i want to animate the UICollectionViewCell
when action is called.
i have done UICollectionViewCell
in Interface Builder
, the UICollectionView
also.
Now i want to get the correct indexPath
at my actionBtnAddToCard
method.
thats the way i try it now (method in 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.
how to acces the correct indexPath?
UPDATE 1: edited post for better understanding.
if you know the view hierarchy it is easy.
UIButton *button = (UiButton *) sender;
if the button is like this - > UITableViewCell - > button
then you can get cell like this
UITableViewCell *cell = (UITableViewCell *)[button superview];
if the button is like this - > UITableViewCell - > content view -> button
UITableViewCell *cell = (UITableViewCell *)[[button superview] superview];
and finally index path can be extracted like this
NSIndexPath *indexPath = [self.table_View indexPathForCell:cell];
- (IBAction)actionAddToCart:(id)sender {
NSIndexPath *indexPath;
indexPath = [self.collectionView indexPathForItemAtPoint:[self.collectionView convertPoint:sender.center fromView:sender.superview]];
...
}
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; indeed, it's not even guaranteed to work on all iOS versions unless you explicitly test it. 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
. Made it a class method since it never references 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:-
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.
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)
You can do it like this, indexPathsForVisibleItems will return array of NSIndexPaths for items currently visible on view and first object returns the first one (if you have one cell per view).
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
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. Just add a property and set the indexPath in cellForItemAtIndexPath.
Xcode10. Swift 4.2 version.
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)
来源:https://stackoverflow.com/questions/13875428/how-to-access-from-uicollectionviewcell-the-indexpath-of-the-cell-in-uicollectio