Reputation: 61
I am new to iOS Programming.I have created custom cell with Three textfield and two button,I have Populated cell count with 10.my textfield working fine.I want to change the button images based on user select.Here My problem is if I change the button images first three cells means,It has repeat for the below cells.I don't know how to handle and how can I find Which button is selected and all.can any one help me.I have tried below codes.
Tableviewcell.m
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
self.textfield1.delegate=self;
self.textfield2.delegate=self;
self.textfield3.delegate=self;
[self.bttn1 addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchUpInside];
[self.bttn2 addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)button1:(UIButton *)sender {
if([_bttn1 isHighlighted]==YES)
{
[_bttn1 setImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
[_bttn2 setImage:[UIImage imageNamed:@"uncheck.png"] forState:UIControlStateNormal];
}
else if([_bttn2 isHighlighted]==YES){
[_bttn1 setImage:[UIImage imageNamed:@"uncheck.png"] forState:UIControlStateNormal];
[_bttn2 setImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)prepareForReuse {
self.textfield1.text = @"";
self.textfield2.text = @"";
self.textfield3.text = @"";
[self.bttn1 setTitle:@"" forState:UIControlStateNormal];
[self.bttn2 setTitle:@"" forState:UIControlStateNormal];
}
//Tableview.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"cellview";
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textfield1.text = _texts[indexPath.row];
cell.textfield1.tag = indexPath.row;
cell.textfield1.delegate = self;
cell.textfield2.text = _texts[indexPath.row+20];
cell.textfield2.tag = indexPath.row+20;
cell.textfield2.delegate = self;
cell.textfield3.text = _texts[indexPath.row+40];
cell.textfield3.tag = indexPath.row+40;
cell.textfield3.delegate = self;
[cell.bttn1 setTitle:@"" forState:UIControlStateNormal];
[cell.bttn2 setTitle:@"" forState:UIControlStateNormal];
return cell;
}
Upvotes: 0
Views: 1690
Reputation: 722
If you just want to change the cell's button image within tap then the baisc logic is :
1. create a custom cell class.
2. add IBOutlet and IBAction of that button on that custom cell class.
3. then add logic in the button's IBAction method.
logic could be : i. self.button1.isSelected
ii. self.button1.isHighlighted etc.
which one you need.
Upvotes: 0
Reputation: 16774
The thing with table views and its cells is they are reused and need to be refreshed fully once a cell is used.
In your case the texts work because you set them inside cellForRowAtIndexPath
method while you leave the selection within the cell. So in your case you need to move the selection into data source. What I mean is you should create a custom class that holds your data for instance:
@interface MyObject: NSObject
@property (nonatomic) BOOL isSelected;
@property (nonatomic, strong) NSString *text1;
@property (nonatomic, strong) NSString *text2;
@property (nonatomic, strong) NSString *text3;
@end
So I am not sure about your _texts[indexPath.row+20]
but from now on let's assume this is mapped to @property (nonatomic, strong) NSArray<MyObject *> *items;
so that code would be changed to:
cell.textfield2.text = [self.items[indexPath.row] text2];
I hope you know how to remap these objects of yours.
Now that we prepared the model we can separate the logic so the cells do what they need to do with the object. There is no reason for view controller to ever touch or even have access to buttons or to text fields. All it needs is to set the item on the cell:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellview" forIndexPath:indexPath];
cell.item = self.items[indexPath.row];
return cell;
}
So then the cell should look like this:
@interface TableViewCell: UITableViewCell
@property (nonatomic, strong) MyObject *item;
@end
And its implementation:
@interface TableViewCell()<UITextFieldDelegate>
@property (nonatomic, strong) UITextField *textfield1;
@property (nonatomic, strong) UITextField *textfield2;
@property (nonatomic, strong) UITextField *textfield3;
@property (nonatomic, strong) UIButton *bttn1;
@property (nonatomic, strong) UIButton *bttn2;
@end
@implementation TableViewCell
- (void)setItem:(MyObject *)item {
_item = item;
[self refresh];
}
- (void)awakeFromNib {
[super awakeFromNib];
self.textfield1.delegate = self;
self.textfield2.delegate = self;
self.textfield3.delegate = self;
}
- (void)refresh {
self.textfield1.text = self.item.text1;
self.textfield2.text = self.item.text2;
self.textfield3.text = self.item.text3;
if(self.item.isSelected) {
[self.bttn1 setImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
[self.bttn2 setImage:[UIImage imageNamed:@"uncheck.png"] forState:UIControlStateNormal];
}
else {
[self.bttn1 setImage:[UIImage imageNamed:@"uncheck.png"] forState:UIControlStateNormal];
[self.bttn2 setImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
}
}
- (void)onButtonPressed:(id)sender {
self.item.isSelected = sender == self.bttn2; // At least it seems this is what you are doing
[self refresh]; // Will reload the whole UI depending on the model changes
}
// TODO: add text field delegate methods as you used them inside your view controller
@end
So to clear things a bit: Your view controller holds an array of all items. Each of the cell gets one item which it can modify at any time. When cell modifies an item it is the same item in the view controller array so updates are reflected. This should be enough in your case but in general you might need the controller to know that a cell triggered something like a button pressed. In those cases you need to use delegates. For instance like so:
@protocol TableViewCellDelegate
- (void)tableViewCell:(TableViewCell *)sender requestSpecialActionForObject:(MyObject *)item;
@end
Then add a property in table view cell:
@interface TableViewCell: UITableViewCell
@property (nonatomic, strong) MyObject *item;
@property (nonatomic, weak) id<TableViewCellDelegate> delegate;
@end
Add extra code to view controller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellview" forIndexPath:indexPath];
cell.item = self.items[indexPath.row];
cell.delegate = self;
return cell;
}
- (void)tableViewCell:(TableViewCell *)sender requestSpecialActionForObject:(MyObject *)item {
// TODO: code here
}
And some logic inside the cell:
- (void)onSpecialButtonPressed:(id)sender {
[self.delegate tableViewCell:self requestSpecialActionForObject:self.item];
}
Upvotes: 0
Reputation: 749
You should create separate class of type UITableViewCell for your cell
TableViewCell.h
@protocol TableViewCellDelegate <NSObject>
-(void)selectedButton:(int)button rowNumber:(int)row;
@end
@interface TableViewCell : UITableViewCell <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *textfield1;
@property (weak, nonatomic) IBOutlet UITextField *textfield2;
@property (weak, nonatomic) IBOutlet UITextField *textfield3;
@property (weak, nonatomic) IBOutlet UIButton *bttn1;
@property (weak, nonatomic) IBOutlet UIButton *bttn2;
@property (nonatomic, weak) id <TableViewCellDelegate> delegate;
-(void)setupView:(int)selectedButton;
@end
TableViewCell.m
#import "TableViewCell.h"
@implementation TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
self.textfield1.delegate=self;
self.textfield2.delegate=self;
self.textfield3.delegate=self;
[self.bttn1 addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchUpInside];
[self.bttn2 addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)button1:(UIButton *)sender {
if(sender == self.bttn1){
[self.delegate selectedButton:1 rowNumber:(int)self.tag];
}
else if([_bttn2 isHighlighted]==YES){
[self.delegate selectedButton:2 rowNumber:(int)self.tag];
}
}
- (void)setupView:(int)selectedButton {
self.textfield1.text = @"";
self.textfield1.tag = self.tag;
self.textfield1.delegate = self;
self.textfield2.text = @"";
self.textfield2.tag = self.tag+20;
self.textfield2.delegate = self;
self.textfield3.text = @"";
self.textfield3.tag = self.tag+40;
self.textfield3.delegate = self;
[self.bttn1 setTitle:@"" forState:UIControlStateNormal];
[self.bttn2 setTitle:@"" forState:UIControlStateNormal];
if (selectedButton == 1) {
self.bttn1.backgroundColor = [UIColor redColor];
self.bttn2.backgroundColor = [UIColor blueColor];
}else if (selectedButton == 2) {
self.bttn1.backgroundColor = [UIColor blueColor];
self.bttn2.backgroundColor = [UIColor redColor];
}else {
self.bttn1.backgroundColor = [UIColor blueColor];
self.bttn2.backgroundColor = [UIColor blueColor];
}
}
@end
ViewController.m
#import "ViewController.h"
#import "TableViewCell.h"
@interface ViewController ()<UITableViewDelegate,UITableViewDataSource,TableViewCellDelegate>
@property (nonatomic, strong)NSMutableArray *arrSelectedBtns;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.arrSelectedBtns = [NSMutableArray array];
for (int i=0; i<10; i++) { //10 respresents number of rows in tableview
[self.arrSelectedBtns addObject:[NSNumber numberWithInt:0]];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellview" forIndexPath:indexPath];
cell.tag = indexPath.row;
cell.delegate = self;
[cell setupView:[[self.arrSelectedBtns objectAtIndex:indexPath.row] intValue]];
return cell;
}
- (void)selectedButton:(int)button rowNumber:(int)row {
[self.arrSelectedBtns insertObject:[NSNumber numberWithInt:button] atIndex:row];
NSIndexPath *indexpath = [NSIndexPath indexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexpath] withRowAnimation:UITableViewRowAnimationNone];
}
@end
Upvotes: 1
Reputation: 423
Here, You have to manage it by array with size of same number of rows, and you have to manage it with conditions in CellForRowAtIndexPath
method
Like,
if (cell.btn.isSelected) {
...
} else {
...
}
Because UITableView
reuses the UITableViewCell
so whatever you have changed will be applied to all.
Upvotes: 0