【问题标题】:Get correct button from custom UICollectionViewCell从自定义 UICollectionViewCell 获取正确的按钮
【发布时间】:2015-06-05 10:40:30
【问题描述】:

我有一个带有自定义 UICollectionViewCell 的自定义 UICollectionView,我的单元格上有一个类似按钮(已连接到 CustomCVCell.h 文件),我需要在按下此按钮时更改它的背景。我所做的是在cellForItemAtIndexPath: 方法上声明按钮的操作,如下所示:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    // Configure the cell
    FolderProducts *item = _feedItems[indexPath.item];

    [cell.like addTarget:self action:@selector(likeProduct:) forControlEvents:UIControlEventTouchUpInside];

    return cell;
}

然后在按钮操作上,我尝试像这样更改背景:

- (void)likeProduct:(UIButton *)button {
        [button setImage:[UIImage imageNamed:@"dislike.png"] forState:UIControlStateNormal];
}

它可以工作,但是其他随机单元格的类似按钮的图像发生了变化,我不明白为什么..

我还尝试使用以下方法检索正确的单元格:

CollectionViewCell *cell = (CollectionViewCell *)button.superview.superview;

然后:

[button setImage:[UIImage imageNamed:@"dislike.png"] forState:UIControlStateNormal];

但结果还是错了

【问题讨论】:

    标签: objective-c uicollectionview uicollectionviewcell


    【解决方案1】:

    问题是由于reusing of the collection view cell 造成的,因为你得到了具有相同图像的随机按钮

    解决方案是维护数组并存储liked 按钮的选定索引路径

    例如你可以像下面那样做

    CustomCVCell.h中定义一个自定义委托

     #import <UIKit/UIKit.h>
    
     @class CustomCVCell; //forword decleration
     @protocol CustomCellDelegate <NSObject>  
      - (void)customCell:(CustomCVCell *)cell actionForButton:(UIButton *)inButton; //hear u are passing the cell and the button
     @end
    
    
     @interface CustomCVCell : UICollectionViewCell
     @property (weak, nonatomic) IBOutlet UIButton *like ; //a button with outlet
     @property (weak, nonatomic) id<CustomCellDelegate> cellDelegate;// define a custom delegate
     - (IBAction)likeProduct:(UIButton *)sender; // set action to cell not in the controller 
    
    //... other code
     @end
    

    CustomCVCell.m

    #import "CustomCVCell.h"
    
    @implementation CustomCVCell
    
    - (id)initWithFrame:(CGRect)frame
    {
       self = [CustomCVCell cell];
       if (self)
       {
    
       }
       return self;
    }
    
    - (void)awakeFromNib {
        // Initialization code
     }
    
    //handle button action in the cell
    - (IBAction)likeProduct:(UIButton *)sender
    {
       //this action you want it to be in controller, call a delegate method
       if([self.cellDelegate respondsToSelector:@selector(customCell:actionForButton:)])
       {
          [self.cellDelegate customCell:self actionForButton:sender]; //implent the action in the controller 
       }
    }
    
    @end
    

    controller

    - (void)viewDidLoad
     {
       [super viewDidLoad];
    
       UICollectionViewFlowLayout *aFlowLayout = [[UICollectionViewFlowLayout alloc]init];
        //..set up code
       [_aCollectionView registerClass:[CustomCVCell class] forCellWithReuseIdentifier:@"CELL"];
    
       likedCells = [[NSMutableArray  alloc]init]; //to hold the index paths of the liked cells
     }
    
    //..other code
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath  
    {
    
      CustomCVCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath];
      if([likedCells containsObject:indexPath]) //based on the indexaths paths u can set the images of the liked cell and if not set nil
      {
         [cell.like setBackgroundImage:[UIImage imageNamed:@"22.jpg"] forState:UIControlStateNormal];
      }
      else
      {
         [cell.like setBackgroundImage:nil forState:UIControlStateNormal];
      }
      cell.backgroundColor = [UIColor greenColor]; //for testing
      cell.cellDelegate = self; //this must be important
      return cell;
    }
    
    //as the like button cliks this method will trigger since u are passing the cell and the button, u can get the index path of the cell 
    - (void)customCell:(CustomCVCell *)cell actionForButton:(UIButton *)inButton
    {
     //hear u will get both cell and its button
     //[inButton setImage:[UIImage imageNamed:@"22.jpg"] forState:UIControlStateNormal];
     [inButton setBackgroundImage:[UIImage imageNamed:@"22.jpg"] forState:UIControlStateNormal]; //set the image
     [likedCells addObject: [_aCollectionView indexPathForCell:cell]]; //and store the index path in the likedCells array
    }
    

    如果你想反转操作同样删除索引路径就是这样

    【讨论】:

      【解决方案2】:

      基本思路是需要将buttons坐标空间转换为collectionviews坐标空间,然后获取indexPath。

      如果你需要使用 Objective-C,让我们创建一个返回给定单元格子视图的 indexPath 的函数:

      - (NSIndexPath *)indexPathForCellContainingView:(UIView *)view inCollectionView:(UICollectionView *)collectionView {
          CGPoint viewCenterRelativeToCollectionView = [collectionView convertPoint:CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)) fromView:view];
          NSIndexPath *cellIndexPath = [collectionView indexPathForItemAtPoint:viewCenterRelativeToCollectionView];
          return cellIndexPath
      }
      

      现在在您的按钮处理程序中:

      - (void)likeProduct:(UIButton *)button {
          [button setImage:[UIImage imageNamed:@"dislike.png"] forState:UIControlStateNormal];
          NSIndexPath *buttonIndexPath = [self indexPathForCellContainingView:button];
          UICollectionViewCell *tappedCell = [collectionView cellForItemAtIndexPath:buttonIndexPath];
      }
      

      请记住,当您的单元格滚动到边界之外时,它将被重复使用,因此您肯定需要跟踪此状态。要么将其持久化到磁盘,要么拥有一个简单的 NSDictionary 来管理每个按钮的状态。

      我在 Swift 中有一个方便的Gist,它也正好解决了 UICollectionView 和 UITableView 的问题。

      herehere也有类似的问题

      【讨论】:

        【解决方案3】:

        为您的按钮分配一个标签以识别它。

        - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
            CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
        
            // Configure the cell
            FolderProducts *item = _feedItems[indexPath.item];
        
            [cell.like addTarget:self action:@selector(likeProduct:) forControlEvents:UIControlEventTouchUpInside];
        cell.like.tag = indexPath.item;
        
            return cell;
        }
        

        然后在实现方法中添加如下代码,

        - (void)likeProduct:(UIButton *)button {
                UIButton *btn = (UIButton *)sender;
                [button setImage:[UIImage imageNamed:@"dislike.png"] forState:UIControlStateNormal];
        }
        

        注意:实现多选/单选的最佳方式是通过与您的喜好相关联的 id。使用集合视图存储该 ID,然后从按钮方法重新加载表格。

        如果您还需要更多帮助,请告诉我..

        【讨论】:

        【解决方案4】:

        您可以在选择器中设置按钮标签和检索标签。

        - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView    cellForItemAtIndexPath:(NSIndexPath *)indexPath {
            CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
        
            // Configure the cell
            FolderProducts *item = _feedItems[indexPath.item];
        
            cell.like.tag = indexPath.item
        
            [cell.like addTarget:self action:@selector(likeProduct:) forControlEvents:UIControlEventTouchUpInside];
        
            return cell;
        
        } 
        

        【讨论】:

        • 那是不必要的,现在您可以在视图中隐式使用标签,有人可能会破坏它。而是将按钮框架转换为集合视图框架并以这种方式获取索引路径stackoverflow.com/a/30665133/1652402
        【解决方案5】:

        因为您没有为单元格中的按钮设置标签。所以这些都是一次选择的。您可以设置他们的标签,如 indexPath.item 并在 didSelectItemAtIndexPath 中捕获他们的标签并选择所需的项目。

        【讨论】:

        • 不要将代码粘贴为图像,如果将其粘贴为文本,则 OP 更容易将其复制到他们的项目中
        • 对不起,丹尼尔首先我试图粘贴我的代码。但是当我点击更新按钮时,它给了我一些错误,比如 4 个空格打算......
        猜你喜欢
        • 2012-03-27
        • 2018-06-23
        • 2018-11-09
        • 2020-05-29
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        • 2016-03-18
        • 1970-01-01
        相关资源
        最近更新 更多