Im trying to add a button into a new cell in a tableview, for example, I need a button under cell '1' if dim is not 0.
However I'm unable to do it. Please enlighten me.
- (void)viewDidLoad
{
[super viewDidLoad];
_displaynum = [NSArray arrayWithObjects:#"1",#"2",#"3", nil];
_displayID = [NSArray arrayWithObjects:#"ID = 1",#"ID = 2",#"ID = 3", nil];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_displaynum count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *lightIdentifier = #"lightIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:lightIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:lightIdentifier];
}
UISwitch *switchLights = [[UISwitch alloc] initWithFrame:CGRectMake(1.0, 1.0, 20.0, 20.0)];
cell.textLabel.text = [_displayLights objectAtIndex:indexPath.row];
cell.detailTextLabel.text =[_displayLightsID objectAtIndex:indexPath.row];
cell.accessoryView = switchLights;
switchLights.on = NO;
int dim = 1;
if ((dim =! 0)) {
NSArray *insertIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:1 inSection:0],
nil];
NSArray *deleteIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:2 inSection:0],nil];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
[tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
return cell;
}
}
First of all, cellForRowAtIndexPath: is not the right place to insert or delete rows the way you are doing.
cellForRowAtIndexPath: gets called every time a new cell is drawn by iOS. So, this is the place where you can modify your cells and simply return it.
That said, this is what you need to do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *lightIdentifier = #"lightIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:lightIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:lightIdentifier];
}
int dim = 1;
if (dim != 0 && indexPath.row == 1) {
CGRect buttonRect = CGRectMake(210, 25, 65, 25);
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = buttonRect;
// set the button title here if it will always be the same
[button setTitle:#"Action" forState:UIControlStateNormal];
button.tag = 1;
[button addTarget:self action:#selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
}
return cell;
}
Related
My recent frustration is a UIButton subview in each UITableViewCell of my UITableView which I want to setHidden: according to a specific clause for each indexPath. My code is pretty much the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[self initCell:cell forIndexPath:indexPath];
}
[self updateCell:cell forIndexPath:indexPath];
return cell;
}
and the init and update methods are the following:
- (void)initCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
...
UIButton *btnMy = [UIButton buttonWithType:UIButtonTypeCustom];
btnMy.tag = kButtonMyTag;
[btnMy setFrame:CGRectMake(170, 45, 100, 30)];
[btnMy setBackgroundImage:[UIImage imageNamed:#"btn_image"] forState:UIControlStateNormal];
btnMy.adjustsImageWhenHighlighted = YES;
[btnMy setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btnMy.titleLabel.font = [UIFont fontWithName:#"MyFont" size:14];
[btnMy addTarget:self action:#selector(btnMyPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:btnMy];
UIImageView *imgViewAccessory = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"table_accessory"]];
cell.accessoryView = imgViewAccessory;
[imgViewAccessory release];
}
- (void)updateCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
UIButton *btnMy = (UIButton *)[cell viewWithTag:kButtonMyTag];
MyObject *object = (MyObject *)[self.dataSource objectAtIndex:indexPath.row];
if(object.meetsCondition)
{
btnMy.hidden = NO;
}
else
{
btnMy.hidden = YES;
}
...
}
The frustrating result is that when scrolling the button shows and hides randomly and not as expected according the if clause in the updateCell method.
Any help would be much appreciated. Thanks in advance!
You should make custom cell and depending upon the condition show and hide the button
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *nib;
static NSString *cellIdentifier= #"cell";
UITableViewCell *theCell = [self.tblView dequeueReusableCellWithIdentifier:cellIdentifier];
if([theCell.contentView subviews]){
for(UIView *view in [theCell.contentView subviews]){
[view removeFromSuperview];
}
}
if(theCell== nil)
{
nib = [[NSBundle mainBundle] loadNibNamed:#"Your custom cell name" owner:self options:nil];
theCell = [nib objectAtIndex:0];
theCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
UIButton *btn=(UIButton*)[theCell.contentView viewWithTag:101];
if(yourcondition)
//hide button
else
//show button
}
This will do
Use this code in your CellForRowAtIndexPath Also.
MyObject *object = (MyObject *)[self.dataSource objectAtIndex:indexPath.row];
if(object.meetsCondition) {
btnMy.hidden = NO;
}
else {
btnMy.hidden = YES;
}
I have a TableView with various entries. Sometimes i need to scroll down, sometimes there are only a few entries, so everything is visible.
I want some settings and filters in my First Cell, but it should not be visible, only when the user scrolls down.
My Trys:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
float rowHeight = [self tableView:self.tableView heightForRowAtIndexPath:indexPath];
self.tableView.contentOffset = CGPointMake(0, rowHeight);
}
and
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTopanimated:NO];
}
Both did not work.
Any advice on my problem?
Are you looking for something like this?
[self.tableView setContentInset:UIEdgeInsetsMake(t,l,b,r)];
this will shift your tableView whatever way you want, but you can definitely scroll back.
Try your logic in the TableView Delegate methods
- (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] autorelease];
}
if (indexPath.row == 0) {
//Your filters here
}
else {
//display the cell
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Also if you dont wish the first cell to be displayed just write
return nil; //for condition of indexpath.row == 0
And also adjust the height for the row in
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section == 0 && isDisplayThisSection) {//first visible
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 5, 320, 25)] autorelease];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(17, 10, 300, 25)];
[titleLabel setFont:[UIFont boldSystemFontOfSize:17.0]];
titleLabel.text = #"Temp Test";
[titleLabel setBackgroundColor:[UIColor clearColor]];
[headerView addSubview:titleLabel];
[titleLabel release];
[headerView setBackgroundColor:[UIColor clearColor]];
return headerView;
}
return [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)] autorelease];
}
set value to 0
Hope this help!!
Try your logic in the TableView Delegate methods
- (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] autorelease];
}
if (indexPath.row == 0) {
//Your filters here
}
else {
//display the cell
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Also if you dont wish the first cell to be displayed just write
return ; //for condition of indexpath.row == 0
And also adjust the height for the row in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
set value to 0
And if you wish to implement like Pull_to_Refresh, you would better write your logic in
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
Hope this help!!
I have a UITableView with different sections and rows. I want to have different label or image like a icone close each cell but I don't know why it's looks like this picture:
Also scrolling changed the size of labels!
Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *key = [[self sectionKeys] objectAtIndex:[indexPath section]];
NSArray *contents = [[self sectionContents] objectForKey:key];
NSString *contentForThisRow = [contents objectAtIndex:[indexPath row]];
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
if(indexPath.row == 0)
{
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(3,0,40,40)];
label.backgroundColor = [UIColor darkGrayColor];
[cell.contentView addSubview:label];
}
else if(indexPath.row == 1)
{
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(3,0,40,40)];
label.backgroundColor = [UIColor redColor];
[cell.contentView addSubview:label]; }
else if(indexPath.row == 2)
{
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(3,0,40,40)];
label.backgroundColor = [UIColor redColor];
[cell.contentView addSubview:label]; }
else{
}
[[cell textLabel] setText:contentForThisRow];
return cell;
}
In your code when user scroll table, labels created many times! You must check if color label already exist in cell and then set color
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int colorLabelTag = 9999;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Because table cells are reusing we must check is label already in cell
UILabel* label = (UILabel *) [cell viewWithTag:colorLabelTag];
// If no - we create label
if (!label) {
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(3,0,40,40)];
label.tag = colorLabelTag;
[cell addSubview:label];
}
if(indexPath.row == 0)
{
label.backgroundColor = [UIColor darkGrayColor];
}
else if(indexPath.row == 1)
{
label.backgroundColor = [UIColor redColor];
}
else if(indexPath.row == 2)
{
label.backgroundColor = [UIColor redColor];
}
[[cell textLabel] setText:contentForThisRow];
return cell;
Unless you want more cusotomizing than this there is no need for subclassing the cell.
Let me give it a try:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *key = [[self sectionKeys] objectAtIndex:[indexPath section]];
NSArray *contents = [[self sectionContents] objectForKey:key];
NSString *contentForThisRow = [contents objectAtIndex:[indexPath row]];
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
// If you need to add more custom views then create them here. E.g.:
UILabel *myLable = [[UILabel alloc] initWithFrame:CGRectMake(10,200,20,20)];
myLable.text = #"Some Value";
label.tag = 101; // use anything but 1. Better use a constant expression.
[cell.contentView addSubview:myLable];
}
switch (indexPath.row) {
case 1:
cell.imageView.image = [UIImage imageNamed:#"red.png"];
break;
case 2:
cell.imageView.image = [UIImage imageNamed:#"blue.png"];
break;
case 3:
cell.imageView.image = [UIImage imageNamed:#"green.png"];
break;
}
UILabel* theLabel = (UILabel *) [cell viewWithTag:101]; // again, a constant is of better style here.
if (theLabel { // it must exist. However, it is good practice to check upon that.
label.text = #"someOtherValue";
}
[[cell textLabel] setText:contentForThisRow];
// you may need to layout your subviews here.
return cell;
}
im trying to implement a tableview with a checkbox on each cell in wish the status(Checked/Unchecked) will get saved on a CoreData data base. i still had no success with the current implementation. If i could get some help i would be very Thankful.
The code in question:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [pictureListData 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];
}
// Get the core data object we need to use to populate this table cell
Compras *currentCell = [pictureListData objectAtIndex:indexPath.row];
BOOL checked = currentCell.status;
UIImage *image = (checked) ? [UIImage imageNamed:#"cb_mono_on#2x.png"] : [UIImage imageNamed:#"cb_mono_off#2x.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame; // match the button's size with the image size
[button setBackgroundImage:image forState:UIControlStateNormal];
// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
cell.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
[self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
}
}
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
Compras *currentCell = [pictureListData objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIButton *button = (UIButton *)cell.accessoryView;
UIImage *image = [UIImage imageNamed:#"cb_mono_on#2x.png"];
// patient.check is a string value set to either "Y" or "N"
// This allows the check mark to be permanently saved
if (currentCell.status) {
image = [UIImage imageNamed:#"cb_mono_off#2x.png"];
currentCell.status = NO;
}
else {
// image defaults to checked.png
image = [UIImage imageNamed:#"cb_mono_on#2x.png"];
currentCell.status = YES;
}
[button setBackgroundImage:image forState:UIControlStateNormal];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Get a reference to the table item in our data array
Compras *itemToDelete = [self.pictureListData objectAtIndex:indexPath.row];
// Delete the item in Core Data
[self.managedObjectContext deleteObject:itemToDelete];
// Remove the item from our array
[pictureListData removeObjectAtIndex:indexPath.row];
// Commit the deletion in core data
NSError *error;
if (![self.managedObjectContext save:&error])
NSLog(#"Failed to delete picture item with error: %#", [error domain]);
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
You wrote in a comment, that currentCell is a NSManagedObject.
As CoreData only can deal with objects, bool values are wrapped with in an instance of NSNumber
BOOL checked = [currentCell.status boolValue];
your code will always result in YES, as you are writing the object's address to the BOOL. and it will most likely never be 0.
I am trying to create a 'blank_star icon' in every cell of a table view, the star should become a 'solid' star after the user clicks on it.
I have created a subclass of UIButton as seen below
//.h file
#interface Bleh : UIButton {
}
+(id)specialInit;
-(void)vvv;
#end
//.m file
#implementation Bleh
+(id) specialInit
{
Bleh* button=[super buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:#"blank_star.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"star.png"] forState:UIControlStateDisabled];
[button addTarget:button action:#selector(vvv) forControlEvents:UIControlEventTouchUpInside];
NSLog(#"%d",[button isEnabled]);
return button;
}
-(void)vvv
{
NSLog(#"button tapped");
[self setEnabled:false];
}
#end
I added the subclass of UIButton in my table view's cellforRow: method as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
int row = indexPath.row;
NSString *cc = [array objectAtIndex:row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure the cell...
Bleh *button = [Bleh specialInit];
button.frame = CGRectMake(0, 0, 100, 100);
NSLog(#"Button:%# at row number: %i",button, indexPath.row);
cell.textLabel.text = cc;
[cell.contentView addSubview:button];
}
return cell;
}
However I am getting an issue when running the app. For instance, if I click on the cell marked 'a', the star becomes solid as expected.
The strange thing is that after scrolling down, I see some other cells with the solid star as well (see cell 'e').
Can anyone help to explain why this is happening? It seems like the state of the cell is being re-used in other cells. How can I avoid this happening?
You can store the state of the button in a NSMutableArray and when you draw the cell you set if it is enabled or disabled based on the NSMutableArray. To change the value on the Array you should Tag the cell and make the change on your vvv selector.
//.h file
#interface Bleh : UIButton {
NSMutableArray *data;
}
On your function
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
// Configure the cell...
Bleh *button = [Bleh specialInit];
[button setTag:row] // row is the id of the button
if([data objectAtIndex:row] isEqualToString:#"ENABLED"]) [button setEnabled:TRUE];
else [button setEnabled:FALSE];
...
}
On your vvv selector
-(void)vvv:(id)sender {
if([sender isEnabled]) {
[sender setEnabled:FALSE];
[data replaceObjectAtIndex:[sender tag] withObject:#"DISABLED"];
}
else {
[sender setEnabled:TRUE];
[data replaceObjectAtIndex:[sender tag] withObject:#"ENABLED"];
}
}
And you should init the array on your viewDidLoad, lets say for 10 cells
- (void)viewDidLoad
{
...
data = [[NSMutableArray alloc] initWithCapacity:10];
for ( int i = 0; i < 10; i++ ) {
[data addObject:#"ENABLED"];
}
...
}
Cells ARE re-used. I had this problem once myself too.
This might be a bit more memory intensive as it doesn't delete old cells from memory, but it does make coding simpler.
One trick is to do this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
NSString *CellIdentifier = [NSString stringWithFormat#"Cell %i", row];
NSString *cc = [array objectAtIndex:row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure the cell...
Bleh *button = [Bleh specialInit];
button.frame = CGRectMake(0, 0, 100, 100);
NSLog(#"Button:%# at row number: %i",button, indexPath.row);
cell.textLabel.text = cc;
[cell.contentView addSubview:button];
}