My app has a favourite button, on clicking it is converting into red heart and if I click againg then it is back to gray heart. Its working correct. But problem is reuseIdentifier,After scrolling, button just coming to original state because its resusing cell here.
How can I save selection of button so that they remain selected(if selected)
Code of tableViewCell class(.h file):
#import <UIKit/UIKit.h>
#interface favBTNTableViewCell : UITableViewCell
#property(nonatomic)UIButton *faVbtn;
#end
Code of tableViewCell class(.m file)
#import "favBTNTableViewCell.h"
#implementation favBTNTableViewCell
#synthesize faVbtn;
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
{
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
faVbtn=[UIButton new];
[faVbtn setFrame:CGRectMake(10, 10, 25, 25)];
[faVbtn setBackgroundImage:[UIImage imageNamed:#"unsel"] forState:UIControlStateNormal];
[faVbtn addTarget:self action:#selector(clickOnfav) forControlEvents:UIControlEventTouchUpInside];
[faVbtn setSelected:YES];
[self.contentView addSubview:faVbtn];
}
return self;
}
-(void)clickOnfav
{
if ([faVbtn isSelected]) {
[faVbtn setBackgroundImage:[UIImage imageNamed:#"sel.jpg"] forState:UIControlStateNormal];
[faVbtn setSelected:NO];
}
else
{
[faVbtn setSelected:YES];
[faVbtn setBackgroundImage:[UIImage imageNamed:#"unsel"] forState:UIControlStateNormal];
}
}
Code of ViewContrller.m
#import "ViewController.h"
#import "favBTNTableViewCell.h"
#interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
{
NSString *ci;
}
#property (strong, nonatomic) IBOutlet UITableView *tv;
#end
#implementation ViewController
-(NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 30;
}
-(UITableViewCell*)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
favBTNTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ci];
if(!cell)
{
cell=[[favBTNTableViewCell alloc]init];
cell.faVbtn.tag=indexPath.row;
}
return cell;
}
- (void)viewDidLoad {
_tv.delegate=self;
_tv.dataSource=self;
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
You need corresponding data source for your cells. For this purpose you can, for example, create one more class and you will use it like an item for data source. Take a look:
#interface DataSourceItem : NSObject
#property (nonatomic, assign) BOOL isFavorite;
#end
#implementation DataSourceItem
#end
Then in view controller's code you need to populate array of data source items and manage your table view depending on this array:
#interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
{
NSString *ci;
}
#property (strong, nonatomic) IBOutlet UITableView *tv;
#property (strong, nonatomic) NSArray *dataSourceArray;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tv.delegate=self;
_tv.dataSource=self;
NSMutableArray *temp = [NSMutableArray new];
// actually how many rows you table view need to have
for (NSUInteger i = 0; i < 30; i++)
{
[temp addObject:[DataSourceItem new]];
}
self.dataSourceArray = [temp copy];**
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// change dataSource item state
DataSourceItem *item = [self.dataSourceArray objectAtIndex:indexPath.row];
item.isFavorite = !item.isFavorite;
// change cell state
favBTNTableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
cell.faVbtn.selected = item.isFavorite;
}
-(NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dataSource count];
}
-(UITableViewCell*)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
favBTNTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ci];
if(!cell)
{
cell=[[favBTNTableViewCell alloc]init];
cell.faVbtn.tag=indexPath.row;
}
// decision based on data source item state
cell.favBtn.selected = self.dataSource[indexPath.row];
return cell;
}
You can fix it like this:
Implement - (void)layoutSubviews method in your custom cell.
In - (void)layoutSubviews, check button state and then set the
right image on it:
->
- (void)layoutSubviews {
[super layoutSubviews];
UIImage *buttonImage = [faVbtn isSelected] ? [UIImage imageNamed:#"sel.jpg"] : [UIImage imageNamed:#"unsel"];
[faVbtn setBackgroundImage:buttonImage forState:UIControlStateNormal];
}
if you are using custom cell
register class/nib for your tableview in did load
[tblName registerNib:[UINib nibWithNibName:#"customCell" bundle:nil] forCellReuseIdentifier:#"customCell"];
henceforth in datasource method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
customCell *cell =(customCell*) [tableView dequeueReusableCellWithIdentifier:#"customCell" forIndexPath:indexPath];
// your code here
return cell;
}
Do not forget to assign your cell identifier as "customCell" in cell attribute
Happy coding..
you can also check similar ans by me
Iphone: Checkmarks in UITableview get mixed up when scrolling
Related
First of all I want to apologize for my bad english.
I'm having trouble to set the properties of my custom UITableViewCell (HistoricoCell).
When I try to set a property of my cell I get: Signal SIGABRT error:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue the cell.
HistoricoCell *cell = (HistoricoCell *)[self.tblHistorico dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// Fetch Item
NSDictionary *item = [self.dbManager.arrColumnNames objectAtIndex:indexPath.row];
// Configure Table View Cell
[cell.lblCodigo setText:[NSString stringWithFormat:#"%#", item[#"codigo"]]];
[cell.btnFavoritar addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
I followed a lot of tutorials and questions on the web but I stil with my error.
Can someone help me?
My code:
HistoricoCell.h
#import <UIKit/UIKit.h>
#interface HistoricoCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *lblCodigo;
#property (weak, nonatomic) IBOutlet UIButton *btnFavoritar;
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tblHistorico;
SecondViewController.m
#import "SecondViewController.h"
#import "DBManager.h"
#import "HistoricoCell.h"
#interface SecondViewController ()
#property (nonatomic, strong) DBManager *dbManager;
#property (nonatomic, strong) NSArray *arrPeopleInfo;
-(void)loadData;
#end
#implementation SecondViewController
static NSString *CellIdentifier = #"CellIdentifier";
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Make self the delegate and datasource of the table view.
self.tblHistorico.delegate = self;
self.tblHistorico.dataSource = self;
// Initialize the dbManager property.
self.dbManager = [[DBManager alloc] initWithDatabaseFilename:#"bernoullidb.sql"];
[self.tblHistorico registerClass:[HistoricoCell class] forCellReuseIdentifier:#"CellIdentifier"];
[self loadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)loadData{
// Form the query.
NSString *query = #"select * from tbHistorico";
// Get the results.
if (self.arrPeopleInfo != nil) {
self.arrPeopleInfo = nil;
}
self.arrPeopleInfo = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
// Reload the table view.
//[self.tblHistorico reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrPeopleInfo.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 60.0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue the cell.
HistoricoCell *cell = (HistoricoCell *)[self.tblHistorico dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// Fetch Item
NSDictionary *item = [self.dbManager.arrColumnNames objectAtIndex:indexPath.row];
// Configure Table View Cell
[cell.lblCodigo setText:[NSString stringWithFormat:#"%#", item[#"codigo"]]];
[cell.btnFavoritar addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (void)didTapButton:(id)sender {
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#end
You should set cell indentifier "CellIdentifier" for your cell in File Inspector
Or register your nib file if you add cell with nib:
UINib *itemNib = [UINib nibWithNibName:#"yourCell" bundle:nil];
[self.tableView registerNib:itemNib forCellReuseIdentifier:#"yourCellReuseIndentifier"];
I think your problem is in your cell creation: you try to dequeue a cell if it exists (i.e. recycle a previously used cell). that is OK, but, especially when the TableView is displayed for the first time, no previously used cell for this table exists. So, you have to create one if the dequeueReusableCellWithIdentifier call return nil.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue the cell.
HistoricoCell *cell = (HistoricoCell *)[self.tblHistorico dequeueReusableCellWithIdentifier:#"HistoricoCellIdentifier" forIndexPath:indexPath];
if( cell == nil ) // no queuded cell to dequeue
{
// you have to create a fresh new one
cell = [HistoricoCell alloc] initWithStyle:<your cell style> reuseIdentifier:#"HistoricoCellIdentifier"];
}
// Fetch Item
NSDictionary *item = [self.dbManager.arrColumnNames objectAtIndex:indexPath.row];
// Configure Table View Cell
[cell.lblCodigo setText:[NSString stringWithFormat:#"%#", item[#"codigo"]]];
[cell.btnFavoritar addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
I'm learning Xcode and programming for the IPad. I have a TableView and can display it using a button. I would rather display it when I click on a TextField. If I dismiss the first responder, the keyboard, how then do I display the tableView? I have not found a example that fits. Any direction would help.
It is just simple
just in UItextField delegate method create your tableview.But return No ,that will never show keyboard and write your tableview code there.
here your have to use user defined delegates.
//firstViewController
***********************
#interface ViewController ()<UITextFieldDelegate,send>
{
UITextField *textField;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
textField=[[UITextField alloc]initWithFrame:CGRectMake(20, 20, 160, 60)];
textField.delegate=self;
textField.backgroundColor=[UIColor greenColor];
[self.view addSubview:textField];
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
TableViewController *table=[[TableViewController alloc]initWithNibName:#"TableViewController" bundle:nil];
table.delegate=self;
[self presentViewController:table animated:YES completion:nil];
return NO;
}
-(void)clickedValue:(NSString *)name
{
textField.text=name;
}
//secondcontroller
*********************
in.h
#protocol send <NSObject>
#required
-(void)clickedValue:(NSString *)name;
#end
#interface........
#property (nonatomic, retain) id<send> delegate;
.m
******
#interface TableViewController ()
{
NSArray *arr;
}
#end
#implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
arr=[[NSArray alloc]initWithObjects:#"murali",#"mohan",nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arr.count;
}
- (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];
}
cell.textLabel.text=[arr objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate clickedValue:[arr objectAtIndex:indexPath.row]];
[self dismissViewControllerAnimated:YES completion:nil];;
}
I am making an app in which i am using tableview and in each table cell i am using checkboxes. now i am stuck in this place that when checkbox is checked i want to get value of that table-cell. like i am showing messages id in table cell i want to get messages_Id of that cells whose checkboxes are checked. means if select 1 checkbox its message id is store in NSString and if i select 2 checkboxes then 2 messages of these checkboxes are store in string how it can be done.below is my sample code of tableview and check boxes action
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *tableviewidentifier = #"cell";
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1){
}
__block NSString *row = [NSString stringWithFormat:#"%ld",(long)indexPath.row];
cell.titlename.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
tocity.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"toCity"];
fromcity.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"fromCity"];
date.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"messageDate"];
time.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"messageTime"];
[cell.button setBackgroundImage:[UIImage imageNamed:#"uncheck.png"] forState:UIControlStateNormal];
[cell.button setImage:nil forState:UIControlStateNormal];
if ([self.checkimageArray containsObject:[self.lblArray objectAtIndex:indexPath.row]])
{
[cell.button setImage:[UIImage imageNamed:#"tick.png"]// here i am setting image
forState:UIControlStateNormal];
cell.contentView.backgroundColor=[UIColor colorWithRed:(245/255.0) green:(245/255.0) blue:(245/255.0) alpha:1];
}
else
{
cell.backgroundColor=[UIColor clearColor];
}
cell.button.tag=indexPath.row;
[cell.button addTarget:self action:#selector(checkButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
and below is my check button code
-(IBAction)checkButton:(UIButton *)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tblvie];
NSIndexPath *indexPath = [self.tblvie indexPathForRowAtPoint:buttonPosition];
if ([self.checkimageArray containsObject:[self.lblArray objectAtIndex:indexPath.row]]) {
[self.checkimageArray removeObject:[self.lblArray objectAtIndex:indexPath.row]];
self.titleLabel.text=#"";
}
else {
[self.checkimageArray addObject:[self.lblArray objectAtIndex:indexPath.row]];
self.titleLabel.text=[NSString stringWithFormat:#"%ld selected",(long)sender.tag+1];
}
[self.tblvie reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation: UITableViewRowAnimationFade];
}
and i want to get value of these checked boxes in this button
- (IBAction)menubtun:(id)sender {
}
there if want the cell info of selected cell, just handle the action method of tickButton in custom cell it self not in controller use below code define a protocol and define a delegate see the below code
in tablecellTableViewCell.h
#import <UIKit/UIKit.h>
#class tablecellTableViewCell;
#protocol CustomCellDelegate <NSObject>
- (void)checkBoxButtonSelected:(tablecellTableViewCell *)cell; //this is the custom delegate method
#end
#interface tablecellTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *profileImageView; //i changed the name for conventions
#property (weak, nonatomic) IBOutlet UIButton *tickButton;
#property (weak, nonatomic) IBOutlet UILabel *nameLabel; //valuedate
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
#property (weak, nonatomic) IBOutlet UILabel *dateLabel;
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
#property (weak, nonatomic) id<CustomCellDelegate> cellDelegate; //decleare a delegate hear
- (void)setFont:(UIFont *)font withString:(NSString *)title;
#end
and in tablecellTableViewCell.m all code is same but u have to connect a action to tickButton for example
#import "tablecellTableViewCell.h"
#implementation tablecellTableViewCell
//#synthesize button,image;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
[super awakeFromNib];
[self setUp];
}
//...same code of yours no need to change just a action method of tick button is added extra
//in this call a delegate method by passing the entire cell itself
- (IBAction)checkButtonAction:(id)sender
{
if([self.cellDelegate respondsToSelector:#selector(checkBoxButtonSelected:)])
{
[self.cellDelegate checkBoxButtonSelected:self];//hear u are passing the enire cell to Fbinbox..controller
}
}
in the controller class .h file
//..same code just confirm to protocol
#interface inboxViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UIActionSheetDelegate,CustomCellDelegate> //confirm to protocol
{
int checkBoxesCount;
}
in .m file
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [tableView dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell == nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
}
__block NSString *row = [NSString stringWithFormat:#"%ld",(long)indexPath.row];
cell.activityIndicatorView.hidden = NO;
[cell.activityIndicatorView startAnimating];
if([[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"messageRead"] intValue]==0)
{
cell.contentView.backgroundColor=[UIColor colorWithRed:(245/255.0) green:(245/255.0) blue:(245/255.0) alpha:1];
}
else
{
cell.contentView.backgroundColor=[UIColor clearColor];
}
cell.messageLabel.text = [[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"toCity"];
cell.cellDelegate = self;//add this one line
//... rest same code but comment the action method of tick button
//..hear in the last
cell.tickButton.tag = indexPath.row;
// [cell.tickButton addTarget:self action:#selector(checkButton:) forControlEvents:UIControlEventTouchUpInside]; //comemnt this line this tickbutton action is in custom cell
}
//now define custom delegate method
- (void)checkBoxButtonSelected:(tablecellTableViewCell *)cell //in this cell contains every thing including message and all
{
//hear u are getting the entire cell
//now u can get the all info stored in this cell
NSIndexPath *indexPath = [self.activitiesTableView_ indexPathForCell:cell];
if ([self.checkimageArray containsObject:[self.lblArray objectAtIndex:indexPath.row]]) {
[self.checkimageArray removeObject:[self.lblArray objectAtIndex:indexPath.row]];
//....other stuff's
//cell.textLabel.text;
//..all info present in the cell
}
else
{
[self.checkimageArray addObject:[self.lblArray objectAtIndex:indexPath.row]];
//..do other stuff
NSString *selectedMessage = cell.messageLabel.text;
//cell.textLabel.text;
//..all info present in the cell
NSLog(#"SELECTED MESSAGE->%#",selectedMessage);
}
[self.activitiesTableView_ reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation: UITableViewRowAnimationFade];
}
This is weird, I know but my [UITableView reloadData] is not removing old cells, like this:
The mess you see happened after I clicked on the + button, came back and changed values again. plus button pushes the navigationController to an another controller, and after I came back with clicking on the back button and changed the value, this is what I see. How is it possible?? I used a custom view (subclassed from UIView), which I created as a UIStepper with a UILabel. Here is the codes, the controller.m, and the .h-.m files for the custom UIView.
controller.m
#interface ViewController ()
#property NSString *docsDir;
#property sqlite3 *DB;
#property NSArray *dirPaths;
#property NSString* databasePath;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property BOOL isCreatedBefore;
#property NSArray *theList;
#end
#implementation ViewController
#synthesize docsDir;
#synthesize DB;
#synthesize dirPaths;
#synthesize databasePath;
- (void)viewDidLoad
{
[super viewDidLoad];
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: [NSString stringWithFormat:#"database.db"]]];
[self createDatabase];
self.theList = [self readAllEntries];
}
-(void) viewWillAppear:(BOOL)animated{
self.theList = [self readAllEntries];
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.theList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ SeriesObject * obj = [self.theList objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellocan"];
UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
[nameLabel setText:obj.name];
CounterView *seasonCounter = [[CounterView alloc] initWithX:220 WithY:28 WithName:obj.name withCount:obj.session withCustomTag:indexPath.row];
seasonCounter.tag = 2;
CounterView *episodeCounter = [[CounterView alloc] initWithX:268 WithY:28 WithName:obj.name withCount:obj.episode withCustomTag:indexPath.row];
episodeCounter.tag = 4;
[cell.contentView addSubview:seasonCounter];
[cell.contentView addSubview:episodeCounter];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you 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) {
SeriesObject *obj = [self.theList objectAtIndex:indexPath.row];
[self deleteEntryWithID:obj.idd];
self.theList = [self readAllEntries];
[self.tableView reloadData];
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 88;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
______and more about reading from database or deleting; not about the view. (this is a very simple app, as a free time hobby; so I didn't spend time to follow MVC)
CounterView.h
#interface CounterView : UIView
#property NSString* name;
#property NSInteger count;
#property UILabel *label;
#property NSInteger customTag;
- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag;
#end
CounterView.m
#interface CounterView()
#property NSString *docsDir;
#property sqlite3 *DB;
#property NSArray *dirPaths;
#property NSString* databasePath;
#end
#implementation CounterView
#synthesize docsDir;
#synthesize DB;
#synthesize dirPaths;
#synthesize databasePath;
- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag
{
self = [super initWithFrame:CGRectMake(xPoint, yPoint, 24, 52)];
if (self) {
self.customTag = newTag;
self.count = newCount;
self.name = newName;
UIButton *btnUp = [[UIButton alloc] initWithFrame:CGRectMake(3, 2, 18, 12)];
[btnUp setImage:[UIImage imageNamed:#"top.png"] forState:UIControlStateNormal];
[btnUp addTarget:self action:#selector(increaseValue) forControlEvents:UIControlEventTouchUpInside];
UIButton *btnDown = [[UIButton alloc] initWithFrame:CGRectMake(3, 38, 18, 12)];
[btnDown setImage:[UIImage imageNamed:#"bottom.png"] forState:UIControlStateNormal];
[btnDown addTarget:self action:#selector(decreaseValue) forControlEvents:UIControlEventTouchUpInside];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 24, 24)];
[self.label setText:[NSString stringWithFormat:#"%ld", (long)self.count]];
self.label.textAlignment = NSTextAlignmentCenter;
[self addSubview:btnUp];
[self addSubview:btnDown];
[self addSubview:self.label];
}
return self;
}
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents{
}
-(void) increaseValue{
self.count++;
[self.label setText:[NSString stringWithFormat:#"%ld", (long)self.count]];
}
-(void) decreaseValue{
self.count--;
[self.label setText:[NSString stringWithFormat:#"%ld", (long)self.count]];
}
____and some more database codes too..
In your cellForRowAtIndexPath: you are adding a subview every time. Cells are reused by UITableView, so when you reload you're getting a "dirty" cell. You need to check if the view is already there. If so, modify the view instead of adding one. Google "UITableViewCell viewWithTag" to see some sample code.
- (void)prepareForReuse
{
//remove your subviews here
[self.subViewToRemove removeFromSuperView];
}
I would recommend that you create a custom cell class derived from UITableViewCell and have it include your custom CounterView instances. In this case you won't need to add the subviews each time in your cellForRowAtIndexPath (Which is causing the problem you're having), you can instead pass it whatever values it requires.
after some modifications, using this in the cellForRowAtIndexpath: method solved everything. Thanks everyone.
if (cell != nil)
{
NSArray* subviews = [cell.contentView subviews];
for (UIView* view in subviews)
{
[view removeFromSuperview];
}
}
I got a button in a tableview cell (named "deleteTemplate"), and when it's pressed i should get the "index.row" for the cell the button is in. Anybody knows how to get the "index.row" for the cell, when you click a button in the cell?
My current code for the button:
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonIndexPath = [self.tableView indexPathForCell:clickedCell];
NSDictionary *dic = [tableData objectAtIndex:clickedButtonIndexPath.row];
But clickedButtonIndexPath = NULL? :(
This worked in iOS 6.
Thank you!!!
You are getting null because the view hierarchy in iOS 7 is changed.
I recommend to use Delegate for getting the indexpath of TableViewCell.
You can get the sample project from here
Here is the sample:
My View Controller looks like this:
//#import "ViewController.h"
//#import "MyCustomCell.h"
#interface ViewController ()
{
IBOutlet UITableView *myTableView;
NSMutableArray *dataSourceArray;
}
#end
#implementation ViewController
-(void)viewDidLoad
{
[super viewDidLoad];
dataSourceArray = [[NSMutableArray alloc] init];
for(int i=0;i<20;i++)
[dataSourceArray addObject:[NSString stringWithFormat:#"Dummy-%d",i]];
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//pragma mark - UITableView Delegate And Datasource -
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return dataSourceArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdenfifier = #"MyCustomCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdenfifier forIndexPath:indexPath];
[cell setDelegate:self];
[cell.myButton setTitle:[dataSourceArray objectAtIndex:indexPath.row] forState:UIControlStateNormal];
return cell;
}
//pragma mark - MyCustomCell Delegate -
-(IBAction)myCustomCellButtonTapped:(UITableViewCell *)cell button:(UIButton *)sender
{
NSIndexPath *indexPath = [myTableView indexPathForCell:cell];
NSLog(#"indexpath: %#",indexPath);
}
#end
MyCustomCell.h looks like this:
//#import
#protocol MyCustomCellDelegate
#optional
- (IBAction)myCustomCellButtonTapped:(UITableViewCell *)cell button:(UIButton *)sender;
#end
#interface MyCustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *myButton;
#property(nonatomic, weak)id delegate;
#end
MyCustomCell.m looks like this:
//#import "MyCustomCell.h"
#implementation MyCustomCell
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
}
return self;
}
-(void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
//#pragma mark - My IBActions -
-(IBAction)myCustomCellButtonTapped:(UIButton *)sender
{
if([self.delegate respondsToSelector:#selector(myCustomCellButtonTapped:button:)])
[self.delegate myCustomCellButtonTapped:self button:sender];
}
#end
you set tag for your button in cellforrowatindexpath
clickedButtonIndexPath.tag=indexpath.row;
when button is presse in action write
nslog(#"%i",btutton.tag);
if clickedbuttonindexpath is nil it wont uitableviewcell
This question is already answered many times. For completion, here is the best solution:
-(IBAction)cellButtonTapped:(UIButton *)sender
{
CGRect buttonFrame = [sender convertRect:sender.bounds toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonFrame.origin];
}
when you make the cell assign at you button.tag the indexPath.row and when you click the button in your method you have the sender (the button) and you get the indexPath from the sender's tag