Adding custom edit and delete button in UITableViewCell - ios

I have a UITableView which contains the names of all countries.
The user can delete or edit the name of country anytime by taping on the cell.
My UITableView cell initially looks like this:
Now when user taps on it I am changing it like this:
I think I am following a very lame approach.Here is what I did:
Declared globally buttons to add:
UIButton *btnDeleteWithImage,*btnDeleteWithText,*btnEditWithImage,*btnEditWihtText; //buttons
And a NSMutableArray to keep track of indexPath.row
Now in my didSelectMethod I am doing this:
//To change the background
UIView *selectionBackground = [[UIView alloc] init];
selectionBackground.backgroundColor = [UIColor customColor];
cell.selectedBackgroundView = selectionBackground;
// to check which cell is pressed
if([indexPathCollection containsObject:index])
{
[btnDeleteWithImage removeFromSuperview];
[btnDeleteWithText removeFromSuperview];
[btnEditWihtText removeFromSuperview];
[btnEditWithImage removeFromSuperview];
[indexPathCollection removeObject:index];
[cell addSubview:btnDeleteWithImage];
[cell addSubview:btnDeleteWithText];
[cell addSubview:btnEditWithImage];
[cell addSubview:btnEditWihtText];
[indexPathCollection addObject:index];
}
else
{
[cell addSubview:btnDeleteWithImage];
[cell addSubview:btnDeleteWithText];
[cell addSubview:btnEditWithImage];
[cell addSubview:btnEditWihtText];
[indexPathCollection addObject:index];
}
But this is not working good.When I scroll table edit and delete button randomly occurs.
Did someone has better Idea how can achieve this in a very efficient way.

You can achieve this by creating a custom cell with your properties
CustomCell.h
#interface CustomCell : UITableViewCell
#property (nonatomic, strong) UIButton *btnDeleteWithImage;
#property (nonatomic, strong) UIButton *btnDeleteWithText;
#property (nonatomic, strong) UIButton *btnEditWithImage;
#property (nonatomic, strong) UIButton *btnEditWithText;
#end
initialize them in cell's init method keeping them hidden at first or you can do
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *customCellIdentifier = #"customCellIdentifier";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:customCellIdentifier];
if (!cell) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:customCellIdentifier];
// or you can initialize and add them to the cell here
}
//here you can modify them accordingly
return cell;
}
then the delegate method can be
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
CustomCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell.btnDeleteWithImage setHidden:NO];
[cell.btnEditWithImage setHidden:NO];
}

the simplest way is that do not reuse the cell . & register your custom cell with same indentifire .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
customCell* cell = [[customCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:#"indentifire"] ;
// manage your plooting here ..
return cell;
}
hope it works for you.

Related

UIStepper over riding the UILabel values in Custom Cell in iOS

I have a UITableViewController which consists of a TableView and a UILabel. UITableViewSource feeds data to the TableView through custom UITableViewCell. UITableViewCell consists of a Stepper which can add items and the Label holds that value.
I want to update the UILabel in UIViewController when the user taps on the Stepper and i cannot seem to get that to work...
Any help/tips are greatly appreciated! Here is sample code from my test project, there is a bunch of unused code but this is just a test so i let it be there.
Thanks,
The Code is
My Custom Cell Class is "StepperDetailsCell".
#interface StepperDetailsCell : UITableViewCell
#property (nonatomic,weak) id <StepperDetailsCellDelegate> delegate;
#property (strong, nonatomic) IBOutlet UIImageView *imagegroceries;
#property (strong, nonatomic) IBOutlet UIStepper *objstepper;
#property (strong,nonatomic) IBOutlet UILabel *lblsteppervalue;
-(IBAction)stepperclicked:(UIStepper*)sender;
#end
and My table view class is named as "SecondViewController"
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"Cell";
cell = (StepperDetailsCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil){
cell = (StepperDetailsCell *)[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
[cell.imagegroceries setImage:[UIImage imageNamed:[[self.didSelectedImages sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]objectAtIndex:indexPath.row]]];
[cell.objstepper addTarget:self action:#selector(stepperValuechanges:) forControlEvents:UIControlEventValueChanged];
cell.lblsteppervalue.text = [self.quantityArr objectAtIndex:indexPath.row];
return cell;
}
pragma mark - Stepper Action Method
-(void)stepperValuechanges:(UIStepper *)sender{
CGPoint stepperPosition = [sender convertPoint:CGPointZero toView:self.tableView];
indexPath1 = [self.tableView indexPathForRowAtPoint:stepperPosition];
if (indexPath1 != nil )
{
float val = sender.value;
valueInt = (int)val;
[self.quantityArr replaceObjectAtIndex:indexPath1.row withObject:[NSString stringWithFormat:#"%i",valueInt]];
NSLog(#"%#",self.quantityMDict);
}
[self.tableView reloadData];
}
Here, Everything is working properly,but whenever new cell is loading from bottom of tableview, then that time new cell stepper act as disappeared cell stepper.
Finally After 3 days I solved my problem.
Just set the value for UIStepper before firing the action of the UIStepper Object to the corresponding Controller Object like the following way..
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"Cell";
cell = (StepperDetailsCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil){
cell = (StepperDetailsCell *)[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
[cell.imagegroceries setImage:[UIImage imageNamed:[[self.didSelectedImages sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]objectAtIndex:indexPath.row]]];
// I just set the previous value(this value, I am taken from the array named "quantityArr") to corresponding stepper, before firing the action to the controller object from the stepper object. That's it..
[cell.objstepper setValue:[[self.quantityArr objectAtIndex:indexPath.row] doubleValue]];
[cell.objstepper addTarget:self action:#selector(stepperValuechanges:) forControlEvents:UIControlEventValueChanged];
cell.lblsteppervalue.text = [self.quantityArr objectAtIndex:indexPath.row];
return cell;
}

iOS - Custom UISwitch in UITableViewCell dealloc error

I am using a UISwitch subclass to add UISwitches to all my UITableViewCells. I use the custom class to be able to pass more info to the UISwitch.
The error I have on iOS 8 ONLY is:
*** -[NamedUISwitch _sendActionsForEvents:withEvent:]: message sent to deallocated instance
NamedUISwitch is the Custom UISwitch I made:
#interface NamedUISwitch : UISwitch
#property (nonatomic, strong) NSString *specialinfo1;
#property (nonatomic, strong) NSString *specialinfo2;
#end
#implementation NamedUISwitch
#end
This is how I implement my UISwitch in the cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] init];
NamedUISwitch *switchview = [[NamedUISwitch alloc] initWithFrame:CGRectZero];
[switchview addTarget:self action:#selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventTouchUpInside];
cell.textLabel.text = ...;
switchview.nomEtablissement = ...;
switchview.tag = ...;
switchview.typeInfo = ...;
cell.accessoryView = switchview;
return cell;
}
I have tried using Instruments to track the dealloc but I can't seem to get it to work the right way.
How can I resolve this dealloc issue?
You are not creating your cells correctly. You need code something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
NamedUISwitch *switchview = nil;
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
switchview = [[NamedUISwitch alloc] initWithFrame:CGRectZero];
[switchview addTarget:self action:#selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = switchview;
} else {
switchview = cell.accessoryview;
}
cell.textLabel.text = ...;
switchview.nomEtablissement = ...;
switchview.tag = ...;
switchview.typeInfo = ...;
// You also need to set switchview.on here
return cell;
}
This way you reuse cells properly and each cell only gets one switch.
An even better option would be to create a custom table cell class and that cell class sets up its own switch.

UILabel appears multiple times in UITableViewCell

I'm currently creating my UITableViewCells programmatically like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Home-Cell" forIndexPath:indexPath];
UILabel *newLabel = [[UILabel alloc] initwithframe:cell.frame];
[newLabel setText:self.data[indexPath.row]];
[cell addSubview:newLabel];
return cell;
}
This seems to create a new UILabel each time the cell is reused though, which I definitely don't want. I tried doing the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Home-Cell" forIndexPath:indexPath];
if (cell == nil) {
UILabel *newLabel = [[UILabel alloc] initwithframe:cell.frame];
[cell addSubview:newLabel];
}
[newLabel setText:self.data[indexPath.row]];
return cell;
}
but then the UILabel seems to never be created. Perhaps this is because I'm using prototype cells with Storyboard and thus the cells are never nil?
You have two solutions.
Create a custom table view cell that already has the label.
If you want to add the label in code, don't register a class for the cell. Then the dequeued cell can be nil and you can add the label at that time (like in your 2nd set of code). This also requires using the dequeueReusableCellWithIdentifier method that doesn't also take an indexPath.
You should create a UITableViewCell subclass and add "newLabel" as a property.
The cell is never nil because the method you use to dequeue the table view cell always returns a cell, creating one if it doesn't already exist in the reuse queue.
A better solution would be to create the label in the cell prototype in the storyboard.
This implementation is against MVC architecture where controller managers stuff and do not deal with view. Here, you are trying to add stuff in view from controller. It is suggested to subclass UITableViewCell as below and add your custom UI controls in there
MyTableViewCell.h
#interface MyTableViewCell : UITableViewCell {
}
#property (nonatomic, strong) UILabel *myLabel;
#end
Then you can implement layoutSubviews in your MyTableViewCell.m file to define the look and feel of your cell.
MyTableViewCell.m
- (id)initWithStyle:(UITableViewCellStyle)iStyle reuseIdentifier:(NSString *)iReuseIdentifier {
if ((self = [super initWithStyle:iStyle reuseIdentifier:iReuseIdentifier])) {
self.myLabel = [[UILabel alloc] initWithFrame:<Your_Frame>];
// Set more Label Properties
[self.contentView addSubview:self.myLabel];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
// Override run time properties
}
Finally use your custom cell like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"Home-Cell" forIndexPath:indexPath];
if (cell == nil) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Home-Cell"];
}
cell.myLabel.text = self.data[indexPath.row];
return cell;
}
As a side note, I hope you know that you get textLabel and detailTextLabel free from default UITableViewCell implementation.

Populating a TableView in ViewDidAppear

I am trying to do what I thought would be simple, but is seems quite complex.
I am trying to create a leaderboard screen.
I have the following:
NSArray* playerNames
NSArray* playerScores
My leaderboard tab is a viewcontroller. Inside, it has a tableview. The tableview has an outlet.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#interface LeaderboardViewController : UIViewController
{
}
- (void)viewDidAppear:(BOOL)animated;
- (void) viewWillDisappear:(BOOL)animated;
#property (weak, nonatomic) IBOutlet UITableView *leaderboardTable;
- (SimonGameModel*) model;
#end
When the view did load, I get the above 2 arrays (both of same length) from my model. They correspond to the latest scores.
What I need is for each table cell to tave 2 lables so that I end up with a leaderboard that looks something like this:
Tim 200
John 100
Jack 50
etc...
I have been reading apple's docs for nearly an hour and I am confused as to how to do this.
I created a prototype with the labels I want.
Thanks
-(void)viewDidLoad {
[leaderboardTable setDataSource:self];
[leaderboardTable setDelegate:self];
}
you must create your custom cell in this way:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [playerNames count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"leader";
UITableViewCell *cell = [leaderboardTable dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UILabel *labelName = [[UILabel alloc] initWhitFrame:CGRectMake(5, 0,160,44);
[labelName setTextAlignment:NSTextAlignmentLeft];
labelName.textColor = [UIColor blackColor];
[cell.contentView addSubView:labelName];
UILabel *labelValue = [[UILabel alloc] initWhitFrame:CGRectMake(165, 0, 150, 44);
[labelValue setTextAlignment:NSTextAlignmentRight];
labelValue.textColor = [UIColor blackColor];
[cell.contentView addSubView:labelValue];
}
labelName.text = [playerNames objectAtIndex:indexPath.row];
labelValue.text = [playerScores objectAtIndex:indexPath.row];
return cell;
}
It sounds like you have not set your LeaderboardViewController as your tableview's dataSource. LeaderboardViewController will have to conform to the UITableViewDataSource protocol:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDataSource_Protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40006941
Also, remember to register a UITableViewCell xib or class with your tableview.
You will be populating your cells with data from your arrays in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

How can i use custom UITableViewCell and UITableView in same xib

I want to use a custom UITableviewCell with UITableView in same xib without creating a UITableViewCell class?
As you can see bellow i set the identifier for UITableViewCell and used it like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
}
But Not Working?
Add a UITableViewCell *customCell property to your view controller (for example, your file ShowUsers.h)...
#property (nonatomic, strong) IBOutlet UITableViewCell *customCell;
and connect it to the custom cell in your xib. Then use the following code in cellForRow (for example, your file ShowUsers.m) :
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"NibName" owner:self options:nil];
cell = self.customCell;
self.customCell = nil;
}
Yes you can do as following code
Under ViewDidLoad or ViewWillAppear
label1Array=[NSMutableArray arrayWithObjects:#"A",#"B",nil];
label2Array=[NSMutableArray arrayWithObjects:#"C",#"D",nil];
label3Array=[NSMutableArray arrayWithObjects:#"E",#"F",nil];
UITableViewDelegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"aCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UILabel *label1=[[UILabel alloc]init];
label1.frame=CGRectMake(0,0,40,40);
label1.text=[label1Array objectAtIndex:indexPath.row];
................
[cell.contentView addSubView: label1];
UILabel *label2=[[UILabel alloc]init];
label2.frame=CGRectMake(50,0,40,40);
label2.text=[label2Array objectAtIndex:indexPath.row];
[cell.contentView addSubView: label2];
UILabel *label3=[[UILabel alloc]init];
label3.frame=CGRectMake(100,0,40,40);
label3.text=[label3Array objectAtIndex:indexPath.row];
[cell.contentView addSubView: label3];
}
Hope this Helps !!!
See..You can do like this. Here you are adding two UITableViewCell in one TableView using XIB.
In Class.h file :-
Declare one mutable array for number of cells.
{
NSMutableArray * sectionRows;
}
#property (nonatomic,retain) IBOutlet UITableViewCell *addTvc1;
#property (nonatomic,retain) IBOutlet UITableViewCell *addTvc2;
In Class.m :-
#synthesize addTvc1, addTvc2;
- (void)viewDidLoad
{
[super viewDidLoad];
sectionRows = [[NSMutableArray alloc] init];
[sectionRows addObject:[[NSMutableArray alloc]
initWithObjects:addTvc1, nil]];
[sectionRows addObject:[[NSMutableArray alloc]
initWithObjects:addTvc2, nil]];
}
In UITableViewDelegate Method -
Add This -
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sectionRows count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section
{
return [[sectionRows objectAtIndex:section] count];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
return [[sectionRows objectAtIndex:indexPath.section]
objectAtIndex:indexPath.row];
}
Along with code, In Class's XIB drop and drag two UITableViewCell which should be outside from the view and add those cells with Files Owner.
It will work perfectly. Here no need to create one separate custom UITableViewCell class.

Resources