如何在单元格中使UIButton在点击后立即保持特定状态?

时间:2014-04-26 11:50:28

标签: ios objective-c cocoa-touch uibutton uicollectionview

所以我在UICollectionView中有一个项目列表,其中有一个UIButton,默认设置为UIImage,设置为浅灰色的心脏和黑色的心脏。

我的目标是允许用户将项目添加到收藏列表中。我在数据库中添加了一个名为“favorite”的列,它的类型为boolean。

客户在项目的单元格中点击心脏。触发一个方法,用户将传递的项目的对象id作为UIButton的titleLabel传递,以从数据库中获取项目,并将收藏列的布尔值更新为“True”。

收藏夹按钮的方法:

- (void)addFavouriteButtonTapped:(UIButton *)sender
{
    NSLog(@"add to favourites button tapped %@", [[sender titleLabel] text]);

    // Set data base favaourite status to 1 (yes)
    PFQuery *query = [PFQuery queryWithClassName:@"Garments"];
    [query getObjectInBackgroundWithId:[[sender titleLabel] text] block:^(PFObject *object, NSError *error) {
        object[@"favourite"] = @YES;
        [object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
            if (!error) {
                [[[UIAlertView alloc] initWithTitle:@"Add Favouite"
                                            message:@"Item successfully added to favourites"
                                           delegate:_thisController
                                  cancelButtonTitle:@"Ok"
                                  otherButtonTitles: nil] show];
            } else {
                NSLog(@"Something went wrong");
            }
        }]; 
    }];   
}

然后在我的cellForItemAtIndexPath中,我有一个if语句,用于设置UIButton的选定状态。

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{

        NSLog(@"cellForItemAtIndexPath");
        // other cell info here deleted to make things clearer

         _addFavouriteButton = [cell addFavouriteButton];


        // if database favourites status is equal to one then set highlighted to (yes)
        if ([object valueForKey:@"favourite"] ==  [NSNumber numberWithBool:YES]) {
            [_addFavouriteButton setSelected:YES];
            NSLog(@"SETTING SELECTED");
        } else if ([object valueForKey:@"favourite"] ==  [NSNumber numberWithBool:NO]) {
            [_addFavouriteButton setSelected:NO];
        }

        [[_addFavouriteButton titleLabel] setText:[object objectId]];

        [_addFavouriteButton addTarget:_thisController action:@selector(addFavouriteButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

        return cell;
}

现在,当我离开视野并且一切都被摧毁然后再次返回时,黑色的心出现在我选择的最喜欢的地方。这可以。我遇到的问题是当我实际选择要添加的项目时,心脏会更新并保持灰色,直到我离开UICollectionView并返回。

我在addFavouriteButtonTapped:方法的主队列中尝试了reloadData 我也尝试重新加载单元格。

这些都不起作用。

我可以将UIButton的状态设置为选中,但是当我滚动时,选择不会保持位置并移动到其他单元格UIButton并使用我实际选择的按钮离开单元格。解决这个问题的唯一方法是留下少数几个,以便我们有一个新的UICollectionView,它使用我数据库中的if语句来确定是否选择了一个单元格。

**My custom cell:**

@interface VAGGarmentCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet PFImageView *imageView;
@property (weak, nonatomic) IBOutlet UIButton *addFavouriteButton;

@property (weak, nonatomic) IBOutlet UITextView *title;
@property (weak, nonatomic) IBOutlet UILabel *price;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;

@end

问题:

我已经完成了大部分需要完成的工作,并且可以在构建列出客户收藏列表中的项目的页面时使用收藏夹列。但是如何在点击按钮并成功更新后立即刷新UICollectionView以显示UIButton的选定状态?

1 个答案:

答案 0 :(得分:1)

确保您也将sender(即已按下的按钮)设置为选中,或者在更新模型后重新加载集合视图。

更新:在聊天讨论后,此答案已经过编辑和更新。

您的视图控制器中iVar(或@property}不需要_addFavouriteButton,按钮变量应该只是一个局部变量。 collectionView:cellForItemAtIndexPath:object:方法 - 首先从修复该方法开始

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
    NSLog(@"cellForItemAtIndexPath");
    // other cell info here deleted to make things clearer

    // Create a local variable for your button - this saves a bit of typing in the rest
    // of the method. You can also use dot notation as its a property
    UIButton *favouriteButton = cell.addFavouriteButton;

    BOOL objectFavourited = [object[@"favourite"] boolValue];
    NSLog(@"Setting selected? %@", objectFavourited ? @"YES" : @"NO");
    favouriteButton.selected = objectFavourited;

    // You should set the title directly on the button (as per the docs - 
    // https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIButton_Class/UIButton/UIButton.html#//apple_ref/occ/instp/UIButton/titleLabel), 
    // you shouldn't touch titleLabel except for styling

    // However you only used the title for seeing which object the favourite button tap was for,
    // so I've commented it out
    // [favouriteButton setTitle:[object objectId] forState:UIControlStateNormal];

    [favouriteButton addTarget:_thisController action:@selector(addFavouriteButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

    return cell;
}

现在按钮的目标方法。在这里,您应该执行以下操作:更新模型,更改按钮状态,然后保存模型。如果模型成功保存,您的用户是否关心 - 不是真的!但是,如果保存失败,则用户需要知道,并且按钮和模型需要恢复到之前的状态。
我非常确定如果保存失败,该对象将处于与尝试保存之前相同的状态 - favourite属性设置为YES。即使它没有,但将其设置回NO无论如何都不会真正重要。

获取按下按钮的项目的indexPath的最佳方法是使用与this answer中的方法类似的方法。它是完成索引路径的完美方式,不需要可怕的标签!

现在我们有了项目的索引路径,您不需要查询该特定对象 - 我们可以使用objectAtIndexPath:直接获取它。

- (void)addFavouriteButtonTapped:(UIButton *)button
{
    // Method adapted for a collection view from the above answer
    CGPoint hitPoint = [button convertPoint:CGPointZero toView:self.collectionView]; 
    NSIndexPath *hitIndex = [self.collectionView indexPathForItemAtPoint:hitPoint];

    // Now get the object for this index
    PFObject *object = [self objectAtIndexPath:hitIndex];

    NSLog(@"add to favourites button tapped %ld - %@", (long)hitIndex.item, [object objectId]); 

    // Now update the model
    object[@"favourite"] = @YES;

    // And the button state
    button.selected = YES;

    // Now save the model to parse
    [object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

        if (!succeeded) {
            // Reset the object back to its previous state
            object[@"favourite"] = @NO;
            // Reload the item to reflect the changes in the model
            [self.collectionView reloadItemsAtIndexPaths:@[hitIndex]];

            // Only bother the user if something bad happened
            [[[UIAlertView alloc] initWithTitle:@"Oops!"
                                        message:@"There was a problem please try again later"
                                       delegate:self
                              cancelButtonTitle:@"Dismiss"
                              otherButtonTitles:nil] show];
        }
    }];
}

您可以重新加载集合视图,但是当您更新该方法中的视图时,实际上并不需要。
但是,如果保存失败,则应重新加载集合视图,因为该按钮可能现在用于集合视图中的其他项目!