UIButtons as checkboxes in tableview - ios

I am new to Objective-C and Xcode so please bear with me.
I have tried to solve this problem for many days now and restraining myself from post. The number of posts I have read regarding UIButtons with Tableviews is a lot and I think I am too dumb to understand why this does not work.
I want to implement a tableview with multiple columns of checkboxes:
1 item1 checkbox checkbox
2 item2 checkbox checkbox
Keep in mind that I am currently trying to implement only 1 column of checkboxes.
I am using coded UIButton and setting their image to one of my images: checkedImage.png, unCheckedImage.png
One string NSArray #"" (with item title) and one NSMutableArray BOOL (value for if checked) for every item.
Problem:
A checked button #index 1-4 will lose its checked image upon scrolling the table view. Index 5 seems to stay put, others not so much.
When debugging the method: -(void)checkboxSelected:(id)sender seems to drag out the right #row(index) and the bool variable seems to be correct but image not.
My thought was that the UIButton changes state, so I implemented the buttonimage on all ControlState, no difference occurred.
Code:
#import "ViewController.h"
#define sectionCount 1
#define itemSection 0
#interface ViewController ()
{
NSArray *items;
NSMutableArray *itemsChecked;
UITableView *_tableView;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
items = #[#"1", #"2",#"3", #"4",#"5", #"6",#"7", #"8",#"9", #"10",#"11", #"12",#"13", #"14"];
itemsChecked = [[NSMutableArray alloc] init];
for(int i = 0; i < 14; i++)
{
[itemsChecked addObject:[NSNumber numberWithBool:false]];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
_tableView = tableView;
return sectionCount;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
switch(section)
{
case itemSection:
{
return [items count];
}
default:
return 0;
}
}
-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case itemSection:
return #"Items";
default:
return #"woot";
}
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:#"itemCell"];
switch(indexPath.section)
{
case itemSection:
cell.textLabel.text = items[indexPath.row];
break;
default:
cell.textLabel.text=#"Unknown";
}
static NSInteger checkboxTag = 123;
NSInteger x,y;x = 100; y = 10;
UIButton *checkbox = (UIButton *) [cell.contentView viewWithTag:checkboxTag];
if (!checkbox)
{
checkbox = [[UIButton alloc] initWithFrame:(CGRectMake(x,y,20,20))];
checkbox.tag = checkboxTag;
[cell.contentView addSubview:checkbox];
}
[checkbox setImage:[UIImage imageNamed:#"notSelectedButton.png"] forState:UIControlStateNormal];
checkbox.adjustsImageWhenHighlighted = YES;
[checkbox addTarget:self action:#selector(checkboxSelected:) forControlEvents:UIControlEventTouchDown];
return cell;
}
-(NSIndexPath *) GetCellFromTableView: (UITableView *)tableView Sender:(id)sender
{
CGPoint position = [sender convertPoint:CGPointZero toView:tableView];
NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:position];
return indexPath;//[tableView cellForRowAtIndexPath:indexPath];
}
-(void)checkboxSelected:(id)sender
{
NSIndexPath *ip = [self GetCellFromTableView:_tableView Sender:sender];
NSInteger row = ip.row;
bool checked = [[itemsChecked objectAtIndex:row] boolValue];
if (checked)
{
[(UIButton *)sender setSelected:false];
itemsChecked[row] = #NO;
checked = NO;
}
else
{
[(UIButton *)sender setSelected:true];
itemsChecked[row] = #YES;
checked = YES;
}
UIButton* checkbox = sender;
if (checked)
{
[checkbox setImage:[UIImage imageNamed:#"checkedButton.png"] forState:UIControlStateNormal];
[checkbox setImage:[UIImage imageNamed:#"checkedButton.png"] forState:UIControlStateDisabled];
[checkbox setImage:[UIImage imageNamed:#"checkedButton.png"] forState:UIControlStateApplication];
[checkbox setImage:[UIImage imageNamed:#"checkedButton.png"] forState:UIControlStateHighlighted];
[checkbox setImage:[UIImage imageNamed:#"checkedButton.png"] forState:UIControlStateReserved];
[checkbox setImage:[UIImage imageNamed:#"checkedButton.png"] forState:UIControlStateSelected];
}
else
{
//[checkbox setImage:[UIImage imageNamed:#"notSelectedButton.png"] forState:UIControlStateNormal];
}
}
#end
Header
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource>
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
-(UITableViewCell *) GetCellFromTableView: (UITableView *)tableView Sender:(id)sender;
-(void)checkboxSelected:(id)sender;
#end

1) Don't make items an array of strings, make it an array of custom objects that contain both the string you want to display and a BOOL member variable that remembers whether it is selected or not.
2) Only set your image during the cellForRowAtIndexPath method, not in other methods, and do it differently depending on the state of the BOOL variable mentioned above.
3) When the selected state changes due to your action method (or whatever) it should only change the BOOL state variable and then tell the table view to reload its data (which will trigger cellForRowAtIndexPath).

Related

delete table view multiple rows from a custom button action using [self.tableView deleteRowsAtIndexPaths withRowAnimation in objective c?

i have a edit button and delete button. when edit button tap table view set editing mode on from left side of table view.i already do this. but when select row and tap to the delete button how to use this method
[self.tableView deleteRowsAtIndexPaths=#"indexpath" withRowAnimation:UITableViewRowAnimationAutomatic];
i can delete data but can not use this method from delete method. i need it because after delete button tap, set editing mode gone, and table view update with animation. if i reload table view its not animated.
Try this
-(void)onButtonTap:(UIButton *)sender {
UITableViewCell *cell = (UITableViewCell *)sender.superview;
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
int index = indexPath.row;
[arrDataSource removeObjectAtIndex:index];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
I created Custom Button Edit and Delete with action.Delete button deletes the row successfully.It works fine.I worked with sample one for your question.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableViewDeleterow;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arrTableData;
}
#end
#implementation ViewController
#synthesize tableViewDeleterow;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrTableData = [[NSMutableArray alloc]initWithObjects:#"iPhone",#"iPad",#"iTV",#"iWatch",nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//UITableView DataSource methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrTableData.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCell = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCell];
}
//Custom Edit Button
UIButton *btnEdit = [UIButton buttonWithType:UIButtonTypeCustom];
btnEdit.frame = CGRectMake(0,4,100, 20);
[btnEdit setTitle:#"Edit" forState:UIControlStateNormal];
[btnEdit setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnEdit addTarget:self action:#selector(actionEdit:) forControlEvents:UIControlEventTouchUpInside];
btnEdit.tag = indexPath.row;
[cell.contentView addSubview:btnEdit];
//Custom Delete Button
UIButton *btnDelete = [UIButton buttonWithType:UIButtonTypeCustom];
btnDelete.frame = CGRectMake(250,4,100, 20);
[btnDelete setTitle:#"Delete" forState:UIControlStateNormal];
[btnDelete setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnDelete addTarget:self action:#selector(actionDelete:) forControlEvents:UIControlEventTouchUpInside];
btnDelete.tag = indexPath.row;
[cell.contentView addSubview:btnDelete];
return cell;
}
-(void)actionEdit:(UIButton *)sender
{
//do stuff here for edit action
}
-(void)actionDelete:(UIButton *)sender
{
UITableViewCell *cell = (UITableViewCell*) sender.superview.superview;
NSIndexPath *indexPath = [tableViewDeleterow indexPathForCell:cell];
NSLog(#"The selected indexPath.row is - %ld",(long)indexPath.row);
[arrTableData removeObjectAtIndex:indexPath.row];
[tableViewDeleterow deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
}
#end
When I delete the 2nd index path delete row,the printed result is
The selected indexPath.row is - 2
At intial
After deleting the second index path row delete button

ios-how to save state of button after application close?

I struggle for few days and searched before.
I have button in UITableViewCell for favorite cell.
How to save state of button (selected button load image "fav.png" and normal button load "unfav.png") after application close?
// BirdsTableViewController.m
// iranbirdtest2
//
// Created by Mehdi on 9/27/15.
// Copyright (c) 2015 Mehdi.n13. All rights reserved.
// after 15 azar-21 mehr
#import "BirdsTableViewController.h"
#import "Bird.h"
#import "GeneralViewController.h"
#import "FavoriteTableViewController.h"
#import "MyManager.h"
//NSMutableArray *favoritesArray;
#interface BirdsTableViewController (){
}
#property (strong, nonatomic) UITabBarController *myTabbarController;
#property (strong, nonatomic) GeneralViewController *myFirstViewController;
#end
#implementation BirdsTableViewController
{
}
- (IBAction)buttonTouchDown:(UIButton *)sender {
sender.selected = !sender.selected; //to switch from selected to unselected
//OR in IBaction we can use:
/*
if ([sender isSelected]) {
[sender setImage:[UIImage imageNamed:#"unfav.png"] forState:UIControlStateNormal];
[sender setSelected:NO];
} else {
[sender setImage:[UIImage imageNamed:#"fav.png"] forState:UIControlStateSelected];
[sender setSelected:YES];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey: #"someKey"];
}
*/
}
- (void) viewDidLoad {
[super viewDidLoad];
for (NSIndexPath *indexPath in [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"mySavedMutableArray"]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
self.title=#"پرندگان ایران";
self.tableView.delegate = self;
self.tableView.dataSource = self;
//create array
birds=[[NSMutableArray alloc]init];
// UIButton* myButton;
Bird *bird=[[Bird alloc]init];
bird.name=#"زنبور خوار";
bird.filename=#"bird1";
bird.detail=#"این قسمت مربوط به توضیح می باشد";
[birds addObject:bird];
bird=[[Bird alloc]init]; //dont forget reuse
bird.name=#"زاغ";
bird.filename=#"bird2";
bird.detail=#"توضیحات مربوط به شماره ۲";
[birds addObject:bird];
bird=[[Bird alloc]init];
bird.name=#"طوطی";
bird.filename=#"bird3";
bird.detail=#"توضیحات مربوط به شماره سومی";
[birds addObject:bird];
//add more later
MyManager *sharedManager = [MyManager sharedManager];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
//this is for page view controller:
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"common_bg"]];
self.tableView.backgroundColor = [UIColor clearColor];
UIEdgeInsets inset = UIEdgeInsetsMake(5, 0, 0, 0);
self.tableView.contentInset = inset;
[self.tableView setSeparatorStyle:UITableViewCellSelectionStyleNone]; //delete sepreate line odf tables
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) viewWillDisappear:(BOOL)animated{
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return birds.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
// Configure the cell...
tableView.allowsSelection=YES;
Bird *current=[birds objectAtIndex:indexPath.row];
UIImageView *birdImageView = (UIImageView *)[cell.contentView viewWithTag:100];
birdImageView.image = [UIImage imageNamed:current.filename];
UILabel *name = (UILabel *)[cell.contentView viewWithTag:101];
name.text=[current name];
//button code in table view
UIButton *button=(UIButton *) [cell.contentView viewWithTag:103];//fav
[button setImage:[UIImage imageNamed:#"unfav.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"fav.png"] forState:UIControlStateSelected];
button.frame = CGRectMake(0,0, 50, 50);
button.tag = indexPath.row;
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button]; // add the button to the cell
[cell.contentView bringSubviewToFront:button];
// Assign our own background image for the cell
UIImage *background = [self cellBackgroundForRowAtIndexPath:indexPath];
UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.image = background;
cell.backgroundView = cellBackgroundView;
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sepratortable.png"]];
[imgView sizeToFit];
[cell.contentView addSubview:imgView];
return cell;
}
-(void)buttonPressed:(UIButton *)sender
{
NSLog(#"Button Pressed");
MyManager *sharedManager = [MyManager sharedManager];
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell*)sender.superview.superview];
if([sharedManager.favoritesArray containsObject:[birds objectAtIndex:indexPath.row]])
{
[sharedManager.favoritesArray removeObject:[birds objectAtIndex:indexPath.row]];
[self.tableView reloadData];
}
else
{
[sharedManager.favoritesArray addObject:[birds objectAtIndex:indexPath.row]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Do you want to say hello?" message:#"More info..." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Say Hello",nil];
[alert show];
; //we can remove later
}
//save favorite array in plist.
[NSKeyedArchiver archiveRootObject:sharedManager.favoritesArray toFile:#"/Users/Mehdi/Desktop/Project/Backup/21 mehr/fav.plist"];
NSLog(#"Favoritearray : %d",sharedManager.favoritesArray.count);
/*
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setValue:birds forKey:#"key"];
[[NSUserDefaults standardUserDefaults] synchronize];
*/
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (UIImage *)cellBackgroundForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger rowCount = [self tableView:[self tableView] numberOfRowsInSection:0];
NSInteger rowIndex = indexPath.row;
UIImage *background = nil;
if (rowIndex == 0) {
background = [UIImage imageNamed:#"cell_top.png"];
} else if (rowIndex == rowCount - 1) {
background = [UIImage imageNamed:#"cell_bottom.png"];
} else {
background = [UIImage imageNamed:#"cell_middle.png"];
}
return background;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Navigation
/*
In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
UITabBarController *pvc=[segue destinationViewController];
// Pass the selected object to the new view controller.
//what row selected?
NSIndexPath *path=[self.tableView indexPathForSelectedRow];
Bird *c =birds[path.row];
}
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/* if ([segue.identifier isEqualToString:#"ShowGeneralView"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
GeneralViewController *destViewController = segue.destinationViewController;
destViewController.currentbird = [birds objectAtIndex:indexPath.row];
}
*/
self.myTabbarController = (UITabBarController*) [segue destinationViewController];
self.myFirstViewController = [self.myTabbarController.viewControllers objectAtIndex:0];
NSIndexPath *path=[self.tableView indexPathForSelectedRow];
Bird *c =birds[path.row];
_myFirstViewController.currentbird=c;
}
#end
I have no problem for save favorite row after application close.
Problem is with button state that can't save and retrieve.
I know I must use NSUserDefaults, but how?
It seems as though your favorites button is in a cell, and when the button is pressed, you add or remove the favorites from the birds array. You even seem to be storing the plist for a file for persistent storage between app launches. Unless I'm missing something, you need to set the state of the button in the cellForRowAtIndexPath when you build the row. Simply check the favorites array for the cell you are building and if it is in there, set the image to the correct state.
One thing to watch out for is that you need to set it regardless of what you think the default state for the image is. This is because cells are reused (for memory efficency). So let's say you build your cell with a default image state of a gray cell. The user clicks the favorite icon and you set it to the red heart. Then when the user scrolls the cell off the screen, iOS will reuse the cell and the image will still be set to the red image. If you don't explicitly set it to gray if the row is not in your favorites, it will stay red.
Also, as you allude to in your question, you could use NSUserDefaults to store your favorites array, rather than a file (and it would probably be simpler). It would also allow you to use iCloud to sync the user favorites across devices (with a bit more work to handle merge conflicts). There are plenty of resources for how to store data in NSUserDefaults.
In your cellForRowAtIndexPath, you would want to do something like the following:
if([sharedManager.favoritesArray containsObject:[birds objectAtIndex:indexPath.row]])
{
[button setSelected:NO];
} else {
[button setSelected:YES];
}
Also, in your buttonPressed method, you should be toggling the selected state of your button using
sender.selected = !sender.selected;
I would get rid of the (IBAction)buttonTouchDown: method and put all the button handling logic in the buttonPressed method. Having that logic in two places will cause confusion.

Getting buttons inside tableview

I want to add button inside UITableView with drag and drop but i don't know how to call them inside UITableviewCell.You can see a keyword Desc where I have to set them as button title so that I can get all values which I placed in coreData frameWork.
-(void)setquestions:(int)qid
{
NSManagedObject *singleobject = nil;
singleobject = AllQuestions[qid];
NSString * desc=[singleobject valueForKey:#"questionDesc"];
questionlabel.text=desc;
int qidns=[[singleobject valueForKey:#"questionId"]intValue];
NSArray *dummy=[self getoptions:qidns];
NSLog(#"--inside setquestion-%lu",(unsigned long)dummy.count);
for (int i=0; i<dummy.count; i++) {
NSManagedObject *singleobject = nil;
singleobject = dummy[i];
NSString * desc=[singleobject valueForKey:#"optionDesc"];
[self addbutton:desc bid:i];
}
}
-(void)addbutton:(NSString *)desc bid:(int)bid{
[[QBFlatButton appearance] setFaceColor:[UIColor colorWithWhite:0.75 alpha:1.0] forState:UIControlStateNormal];
[[QBFlatButton appearance] setSideColor:[UIColor colorWithWhite:0.55 alpha:1.0] forState:UIControlStateNormal];
optionButton = [QBFlatButton buttonWithType:UIButtonTypeCustom];
optionButton.faceColor = [UIColor colorWithRed:0.400f green:0.737f blue:0.761f alpha:1.00f];
optionButton.sideColor = [UIColor colorWithRed:0.400f green:0.737f blue:0.761f alpha:1.00f];
optionButton.radius = 4.0;
optionButton.margin = 4.0;
optionButton.depth = 3.0;
[optionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
optionButton.titleLabel.font=[UIFont systemFontOfSize:12];
optionButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
// you probably want to center it
optionButton.titleLabel.textAlignment = NSTextAlignmentCenter;
optionButton.tag=bid;
[optionButton setTitle:desc forState:UIControlStateNormal];
optionButton.frame = CGRectMake(5,bid*55,optionsview.frame.size.width-10, 50);
[optionsview addSubview:optionButton];
}
- (void)logItems {
int index = 0;
for ( NSString *str in self.items ) {
NSLog(#"%d: %#", index++, str);
}
}
#pragma mark - UITableViewDataSource, UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:#"Cell"];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
return cell;
}
#pragma mark - Edit Mode
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone; // No Delete icon
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
[table deselectRowAtIndexPath:indexPath animated:YES];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Can move cell
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSUInteger origins = sourceIndexPath.row; // Original position
NSUInteger to = destinationIndexPath.row; // Destination position
NSLog(#"Origin %lu, To %lu", (unsigned long)origins, (unsigned long)to);
NSString *swap = [self.items objectAtIndex:origin];// Item
[swap shouldGroupAccessibilityChildren];
}
As I understood from the question you want to get the button in the cell for that you can create a custom cell class and then call this custom cell inside the cellforrow function. You can call the button like this
customCell.button.title = "some-string"
If you want a custom button with a particular action added to each of the cells, first you need to create a custom UI cell(using XIB since you need to drag and drop). Then add the button to that, and connect the button's IBAction and IBOutlet to the custom subclass for the cell. Next Add a protocol with a function to the cell subclass so that you can send a callback to the ViewController when the button is clicked. Now implement the delegate in the ViewController and use this cell for your purpose. If the delegate function returns the cell, you can figure out which cell's button is clicked, hence getting the indexpath to perform required action.

Set button tag for different sections of UITableView

I list of contacts from Web Service and display it in contacts 'sectioned' tableView as seen in the screenshot.
Issue is I get same tag values for checkboxes of first row for section A as well as section S. I have sorted one array and displayed in the indexed table view. How to get different tag values depending on indexPath.row irrespective of number of sections displayed. Here's what I tried
In cellForRowAtIndexPath:
UIButton *checkBox;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
checkBox = [[UIButton alloc]initWithFrame:CGRectMake(7, 8, 30, 30)];
}
else
{
checkBox = [[UIButton alloc]initWithFrame:CGRectMake(15, 13, 30, 30)];
}
//int cnt = 0;
// for (int i = indexPath.section - 1; i > 0 ; i--)
// {
// cnt += [[objectsForCharacters objectForKey:[arrayOfCharacters objectAtIndex:i]] count]; //arrayOfCharachters has char 'A' to 'Z'
// }
//checkBox.tag = cnt + indexPath.row;
[checkBox setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
[checkBox addTarget:self action:#selector(checkBoxClicked:) forControlEvents:UIControlEventTouchUpInside];
[checkBox setTag:indexPath.row];
[cell.contentView addSubview:checkBox];
return cell;
}
-(void)checkBoxClicked:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableViewContact];
NSIndexPath *indexPath = [self.tableViewContact indexPathForRowAtPoint:buttonPosition];
UIButton *tappedButton = (UIButton*)sender;
NSLog(#"Tag number = %d", [sender tag]);
if([tappedButton.currentImage isEqual:[UIImage imageNamed:#"checkBox.png"]])
{
[sender setImage:[UIImage imageNamed: #"checkBoxMarked.png"] forState:UIControlStateNormal];
if(indexPath != Nil)
{
NSString *finalIntId = [mutableArrayOfIds objectAtIndex:indexPath.row]; // store check box ids in mutableArrayOfIds
NSLog(#"Tagged checked button id = %#", finalIntId);
[arrayOfIds addObject:finalIntId];
}
//NSString *finalIntId = [mutableArrayOfIds objectAtIndex:tappedButton.tag];
//NSString *finalIntId = [mutableArrayOfIds objectAtIndex:indexPath.row];
}
else
{
[sender setImage:[UIImage imageNamed:#"checkBox.png"]forState:UIControlStateNormal];
NSLog(#"UnChecked");
//[arrayOfIds removeObjectAtIndex:tappedButton.tag];
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if ([arrayOfCharacters count] == 0)
{
return #"";
}
return [NSString stringWithFormat:#"%#", [arrayOfCharacters objectAtIndex:section]];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSArray *toBeReturned = [NSArray arrayWithArray:
[#"A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|#"
componentsSeparatedByString:#"|"]];
return toBeReturned;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
NSInteger count = 0;
for (NSString *character in arrayOfCharacters) {
if ([character isEqualToString:title]) {
return count;
}
count ++;
}
return 0;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrayOfCharacters count];
//return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//return [mutableArray count];
return [[objectsForCharacters objectForKey:[arrayOfCharacters objectAtIndex:section]] count];
}
you are setting the same tag value for all sections which have same row.
The indexPath has two properties, {section,row}.
Lets say section A has two rows,
for row1 -> indexPath.section=0, indexPath.row=0;
for row2-> indexPath.section=0, indexPath.row=1;
Lets say section S has two rows,
for row1 -> indexPath.section=1, indexPath.row=0;
for row2-> indexPath.section=1, indexPath.row=1;
So, for row1 of section A and row1 of section S, you are setting the same tag value which is 0.There is your problem.
Try setting tag value like below.
button.tag = indexPath.section*1000 +indexPath.row;
when retrieving the section and row,
NSInteger section = (button.tag)/1000;
NSInteger row = (button.tag)%1000;
Try this...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UIButton *checkBox =[[UIButton alloc] initWithFrame:CGRectMake(280, 10, 50, 44)];
checkBox.backgroundColor =[UIColor orangeColor];
[checkBox addTarget:self action:#selector(checkBoxClicked:event:)forControlEvents:UIControlEventTouchUpInside];
[checkBox setTag:indexPath.row];
[cell.contentView addSubview:checkBox];
return cell;
}
- (void)checkBoxClicked:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tv]; //here tv is TableView Object
NSIndexPath *indexPath = [self.tv indexPathForRowAtPoint: currentTouchPosition];
NSLog(#"value of indePath.section %d ,indexPath.row %d",indexPath.section,indexPath.row);
}
This is happening because you are assigning tag to buttons INDEPENDENT of sections.
Both of First Row of Sections A & S have row = 0. so Tag Assigned to their respective button is 0. You should assign them Keeping reference to your sections.
i would suggest to assign accessibility hint with comma separated form containing Section,Row.
And in your method
-(void)checkBoxClicked:(id)sender
{
//pick string from comma separated form. 1st is your section, 2nd is row.
}
second option is Do what ever your doing and implement your Button method like this.
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
... indexpath.section is your section , index path.row is your row.
}
There is Third option as well.
in cellforRowAtIndexpath assign your Button a title
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
[btn setTitle:<#Your Row#> forState:UIControlStateDisabled];
[btn setTag<#Your Section#>];
so upon Receiving in your Button Method you can have both Section (Tag) and Row (Title for Disabled state).
-(void)checkBoxClicked:(id)sender { [button titleForState:UIControlStateDisabled]; // your Row
button.tag //your Section }
Try this!
Each section you may know the count of section right, then add count of individual row.
[[fieldTitlesList objectAtIndex:indexPath.section - 1] count] + indexPath.row
Where fieldTitlesList is the array of your sections.
I added the following code which solved my issue
NSInteger rowNumber = 0;
for(NSInteger i = 0; i < indexPath.section ; i++)
{
rowNumber += [self tableView:self.tableViewContact numberOfRowsInSection:i];
}
rowNumber += indexPath.row;
[checkBox setTag:rowNumber]; //checkBox is UIButton in cellForRowAtIndexPath

UITableView button duplicates while scrolling

I have created custom buttons for each viewcell(1 per cell). When scrolling the UITableView some viewcells have 2 buttons and that was not intended. I fail to see the error in my ways.
Please help!
Image: http://s18.postimg.org/v7djg84ah/buttons_App.png
Header:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource>
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section;
- (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
-(void)checkboxSelected:(id)sender;
#end
Implementation
#import "ViewController.h"
#define sectionCount 1
#define itemSection 0
#interface ViewController ()
{
NSArray *items;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
items = #[#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2",#"itemdd", #"item2"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return sectionCount;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch(section)
{
case itemSection:
{
return [items count];
}
default:
return 0;
}
}
-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case itemSection:
return #"Items";
default:
return #"woot";
}
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:#"itemCell"];
switch(indexPath.section)
{
case itemSection:
cell.textLabel.text = items[indexPath.row];
break;
default:
cell.textLabel.text=#"Unknown";
}
NSInteger x,y;
x =cell.frame.origin.x +100; y = cell.frame.origin.y + 10;
UIButton *checkbox;
checkbox = [[UIButton alloc] initWithFrame:(CGRectMake(x,y,20,20))];
[checkbox setBackgroundImage:[UIImage imageNamed:#"notSelectedButton.png"]forState:UIControlStateNormal];
[checkbox setBackgroundImage:[UIImage imageNamed:#"checkedButton.png"]forState:UIControlStateSelected];
[checkbox setBackgroundImage:[UIImage imageNamed:#"uncheckedButton.png"]forState:UIControlStateHighlighted];
checkbox.adjustsImageWhenHighlighted = YES;
[checkbox addTarget:self action:#selector(checkboxSelected:) forControlEvents:UIControlEventTouchDown];
[cell.contentView addSubview:checkbox];
return cell;
}
-(void)checkboxSelected:(id)sender
{
bool selected = [(UIButton *)sender isSelected];
if (selected)
{
[(UIButton *)sender setSelected:false];
}
else
{
[(UIButton *)sender setSelected:true];
}
}
#end
First, look at this statement in your code:
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:#"itemCell"];
The method -dequeueReusableCellWithIdentifier will either pull an already created table view cell, or generate a new one if no reusable cell is available.
Now review this statement:
checkbox = [[UIButton alloc] initWithFrame:(CGRectMake(x,y,20,20))];
…
[cell.contentView addSubview:checkbox];
If your cell was just initialized, this code works fine. However, when you scroll your table, your code will start pulling old table view cells that were thrown into the reusable queue. Those old table view cells already contain a UIButton. So every time you call -addSubview: on an old cell, you add duplicate buttons.
There are many ways to fix this. Here's one solution for you:
static NSInteger const checkboxTag = 123;
checkbox = (UIButton *)[cell.contentView viewWithTag:checkboxTag];
if (!checkbox) {
checkbox = [[UIButton alloc] initWithFrame:(CGRectMake(x,y,20,20))];
checkbox.tag = checkboxTag;
[checkbox setBackgroundImage:[UIImage imageNamed:#"notSelectedButton.png"]forState:UIControlStateNormal];
[checkbox setBackgroundImage:[UIImage imageNamed:#"checkedButton.png"]forState:UIControlStateSelected];
[checkbox setBackgroundImage:[UIImage imageNamed:#"uncheckedButton.png"]forState:UIControlStateHighlighted];
checkbox.adjustsImageWhenHighlighted = YES;
[checkbox addTarget:self action:#selector(checkboxSelected:) forControlEvents:UIControlEventTouchDown];
[cell.contentView addSubview:checkbox];
}
EDIT:
Something else worth pointing out. This statement:
x =cell.frame.origin.x +100; y = cell.frame.origin.y + 10;
By referencing cell.frame, you're creating a UIButton relative to the cell's position in the table view, not the cell itself. Set x = 100; y = 10; to make the offset relative to the the cell's bounds instead.

Resources