简体   繁体   中英

Why is my custom accessory button not changing image when tapped (ios)?

I'm trying to make an accessory view similar to Apple's demo , but i must have missed something because mine doesn't switch the image when clicked. It just flickers .

Not sure what i missed, i tried to base it exactly off the demo code. I had to change a couple of dictionaries to mutable and add an if cell null clause to make mine work though.
The items are fetched and displayed properly in the tableview.
I've emboldened the parts that i changed, i think i got them all.

Any help much appreciated thanks.

My code:

Header declaration:

@interface PollQueryController : UIViewController <UITableViewDataSource, UITableViewDelegate>

.m file:

 @interface PollQueryController () @property (nonatomic, strong) NSMutableArray *dataArray; @end @implementation PollQueryController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; // NSString *path = [[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]; // NSDictionary *pollsDictionary = [NSDictionary dictionaryWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]];  // NSMutableArray *choices = [NSMutableArray arrayWithArray:choicesArray]; // Mutable self.dataArray = choices; NSLog(@"array: %@", self.dataArray); // swipe gestures UISwipeGestureRecognizer * Swiperight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swiperight:)]; Swiperight.direction=UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:Swiperight]; UISwipeGestureRecognizer * Swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleft:)]; Swipeleft.direction=UISwipeGestureRecognizerDirectionLeft; [self.view addGestureRecognizer:Swipeleft]; self.title = @"Poll Query"; self.feedTableView.dataSource = self; self.feedTableView.delegate = self; self.feedTableView.backgroundColor = [UIColor whiteColor]; self.feedTableView.separatorColor = [UIColor colorWithWhite:0.9 alpha:0.6]; UIColor* mainColor = [UIColor colorWithRed:50.0/255 green:102.0/255 blue:147.0/255 alpha:1.0f]; NSString* fontName = @"Optima-Italic"; NSString* boldFontName = @"Optima-ExtraBlack"; UIFont* socialFont = [UIFont fontWithName:boldFontName size:10.0f]; UIColor* socialColor = [UIColor lightGrayColor]; } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{ static NSString *kCustomCellID = @"MyCellID"; FeedCell3* cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];   cell.textLabel.text = [item objectForKey:@"text"]; [item setObject:cell forKey:@"cell"]; BOOL checked = [[item objectForKey:@"checked"] boolValue]; UIImage *image = (checked) ? [UIImage imageNamed:@"ticked24"] : [UIImage imageNamed:@"unticked24"]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height); button.frame = frame; [button setBackgroundImage:image forState:UIControlStateNormal]; [button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside]; button.backgroundColor = [UIColor clearColor]; cell.accessoryView = button; UIColor* blueColor = [UIColor colorWithRed:47.0/255 green:168.0/255 blue:228.0/255 alpha:1.0f]; cell.textLabel.textColor = blueColor; NSString* fontName = @"Optima-Italic"; NSString* boldFontName = @"Optima-ExtraBlack"; UIFont* socialFont = [UIFont fontWithName:boldFontName size:10.0f]; cell.textLabel.font = socialFont; cell.textLabel.textAlignment = UITextAlignmentCenter; return cell; } #pragma mark - UITableViewDelegate - (void)checkButtonTapped:(id)sender event:(id)event { NSSet *touches = [event allTouches]; UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self.feedTableView]; NSIndexPath *indexPath = [self.feedTableView indexPathForRowAtPoint: currentTouchPosition]; if (indexPath != nil) { [self tableView: self.feedTableView accessoryButtonTappedForRowWithIndexPath: indexPath]; } } - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {  BOOL checked = [[item objectForKey:@"checked"] boolValue]; [item setObject:[NSNumber numberWithBool:!checked] forKey:@"checked"]; UITableViewCell *cell = [item objectForKey:@"cell"]; UIButton *button = (UIButton *)cell.accessoryView; UIImage *newImage = (checked) ? [UIImage imageNamed:@"unticked24"] : [UIImage imageNamed:@"ticked24"]; [button setBackgroundImage:newImage forState:UIControlStateNormal]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self tableView: self.feedTableView accessoryButtonTappedForRowWithIndexPath: indexPath]; [self.feedTableView deselectRowAtIndexPath:indexPath animated:YES]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)swipeleft:(UISwipeGestureRecognizer*)gestureRecognizer { if(_hasVoted){ [self performSegueWithIdentifier: @"QueryToResults" sender: self]; } } -(void)swiperight:(UISwipeGestureRecognizer*)gestureRecognizer { [self performSegueWithIdentifier: @"friendsBackToPollSeg" sender: self]; } @end\n@interface PollQueryController () @property (nonatomic, strong) NSMutableArray *dataArray; @end @implementation PollQueryController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; // NSString *path = [[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]; // NSDictionary *pollsDictionary = [NSDictionary dictionaryWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]];  // NSMutableArray *choices = [NSMutableArray arrayWithArray:choicesArray]; // Mutable self.dataArray = choices; NSLog(@"array: %@", self.dataArray); // swipe gestures UISwipeGestureRecognizer * Swiperight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swiperight:)]; Swiperight.direction=UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:Swiperight]; UISwipeGestureRecognizer * Swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleft:)]; Swipeleft.direction=UISwipeGestureRecognizerDirectionLeft; [self.view addGestureRecognizer:Swipeleft]; self.title = @"Poll Query"; self.feedTableView.dataSource = self; self.feedTableView.delegate = self; self.feedTableView.backgroundColor = [UIColor whiteColor]; self.feedTableView.separatorColor = [UIColor colorWithWhite:0.9 alpha:0.6]; UIColor* mainColor = [UIColor colorWithRed:50.0/255 green:102.0/255 blue:147.0/255 alpha:1.0f]; NSString* fontName = @"Optima-Italic"; NSString* boldFontName = @"Optima-ExtraBlack"; UIFont* socialFont = [UIFont fontWithName:boldFontName size:10.0f]; UIColor* socialColor = [UIColor lightGrayColor]; } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{ static NSString *kCustomCellID = @"MyCellID"; FeedCell3* cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];   cell.textLabel.text = [item objectForKey:@"text"]; [item setObject:cell forKey:@"cell"]; BOOL checked = [[item objectForKey:@"checked"] boolValue]; UIImage *image = (checked) ? [UIImage imageNamed:@"ticked24"] : [UIImage imageNamed:@"unticked24"]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height); button.frame = frame; [button setBackgroundImage:image forState:UIControlStateNormal]; [button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside]; button.backgroundColor = [UIColor clearColor]; cell.accessoryView = button; UIColor* blueColor = [UIColor colorWithRed:47.0/255 green:168.0/255 blue:228.0/255 alpha:1.0f]; cell.textLabel.textColor = blueColor; NSString* fontName = @"Optima-Italic"; NSString* boldFontName = @"Optima-ExtraBlack"; UIFont* socialFont = [UIFont fontWithName:boldFontName size:10.0f]; cell.textLabel.font = socialFont; cell.textLabel.textAlignment = UITextAlignmentCenter; return cell; } #pragma mark - UITableViewDelegate - (void)checkButtonTapped:(id)sender event:(id)event { NSSet *touches = [event allTouches]; UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self.feedTableView]; NSIndexPath *indexPath = [self.feedTableView indexPathForRowAtPoint: currentTouchPosition]; if (indexPath != nil) { [self tableView: self.feedTableView accessoryButtonTappedForRowWithIndexPath: indexPath]; } } - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {  BOOL checked = [[item objectForKey:@"checked"] boolValue]; [item setObject:[NSNumber numberWithBool:!checked] forKey:@"checked"]; UITableViewCell *cell = [item objectForKey:@"cell"]; UIButton *button = (UIButton *)cell.accessoryView; UIImage *newImage = (checked) ? [UIImage imageNamed:@"unticked24"] : [UIImage imageNamed:@"ticked24"]; [button setBackgroundImage:newImage forState:UIControlStateNormal]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self tableView: self.feedTableView accessoryButtonTappedForRowWithIndexPath: indexPath]; [self.feedTableView deselectRowAtIndexPath:indexPath animated:YES]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)swipeleft:(UISwipeGestureRecognizer*)gestureRecognizer { if(_hasVoted){ [self performSegueWithIdentifier: @"QueryToResults" sender: self]; } } -(void)swiperight:(UISwipeGestureRecognizer*)gestureRecognizer { [self performSegueWithIdentifier: @"friendsBackToPollSeg" sender: self]; } @end 

The issue here is that by using mutableCopy , you instantiate a new object each time. Thus, in your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { call, the checked value of item is always false. I assume there is some kind of tableview reloadData at some point too. Therefore, it sets the accessoryView to the checked image, than reload it, and resets it to the unchecked value because the change to your dataArray item is not persisted (as it is applied to a copy of the object).

Long story short, the item in - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath and - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath are not the same.

edit :

@interface PollQueryController () {
    NSMutableDictionary * _checkStates;
}
    @property (nonatomic, strong) NSMutableArray *dataArray;
@end

@implementation PollQueryController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray * pollsData = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]];
    NSMutableArray * choices = [[[pollsData objectAtIndex:0] objectForKey:@"choices"] mutableCopy]; // mutable
    self.dataArray = choices;
    _checkStates = [[NSMutableDictionary alloc] init];

    NSLog(@"array: %@", self.dataArray);

    […]
}

#pragma mark - UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCustomCellID = @"MyCellID";

    FeedCell3* cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];
// i had to add this, whereas the demo doesnt do this.
       if (cell == nil) {
           cell = [[FeedCell3 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"feedcell3"];
       }

    NSDictionary * item = [self.dataArray objectAtIndex:indexPath.row]
    cell.textLabel.text = [item objectForKey:@"text"];

    NSNumber checkedState = [_checkStates objectForKey:@"item"];
    BOOL checked = checkedState ? [checkedState boolValue] : NO;

    UIImage *image = (checked) ? [UIImage imageNamed:@"ticked24"] : [UIImage imageNamed:@"unticked24"];

    […]

    return cell;
}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *item = [self.dataArray objectAtIndex:indexPath.row];
    NSNumber checkedState = [_checkStates objectForKey:item];
    BOOL checked = checkedState ? YES : ![checkedState boolValue];
    [_checkStates setObject:@(checked) forKey:item];

    // You don't have a reference to the cell here anymore to update the cell accessoryView, but I believe it would be simpler to reload the cell (or the tableView)
    // I'll go with the tableview there for the sake of simplicity, but feel free to update this
    [tableView reloadData];
}
@end

If you don't need mutableCopy ie NSMutableDictionary *item = [self.dataArray objectAtIndex:indexPath.row]; then try relaoding the cell after changing the checked value in accessory button tap, use

- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

method to update the cell,

change - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath method to

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
    NSMutableDictionary *item = [self.dataArray objectAtIndex:indexPath.row];

    BOOL checked = [[item objectForKey:@"checked"] boolValue];

    [item setObject:[NSNumber numberWithBool:!checked] forKey:@"checked"];

    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

wow. I found why it wasnt working for me without using the mutableCopy's.
The original array was not mutable

NSArray * pollsData = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]];

Changing to mutable fixed the issue.

NSMutableArray * pollsData = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pollData" ofType:@"plist"]];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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