I have a code for a table view with a cell that i created. Each cell holds three buttons. Each button should have an image as a background image.
This is my code for the CellForRowArIndex:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CellView" owner:self options:nil];
cell = nibLoadedCell;
}
for (int i = 1; i < 4; i++) {
//----- select the correct button from the cell
button = (UIButton *)[cell viewWithTag:(i)];
//----- cleaning the button, drawing it's corners, borders and giving it an action
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
button.layer.borderWidth = 2;
button.layer.cornerRadius = 5;
button.clipsToBounds = YES;
//------ Setting up the btnImg in order to place on the buttons (if is for checking i'm not taking pictures out of the array bounds)
UIImage *btnImg = [[UIImage alloc] init];
if (((indexPath.row * 3) + i - 1) < photosArray.count) {
btnImg = [photosArray objectAtIndex:((indexPath.row * 3) + i - 1)];
//NSLog(#"I am at indexpath.row: %d",indexPath.row);
//NSLog(#"I show image number %d in the array",[photosArray indexOfObject:btnImg]);
NSLog(#"Expression is: %d",((indexPath.row * 3) + i - 1));
}
//------ Add btnImg to the button
[button setBackgroundImage:btnImg forState:UIControlStateNormal];
//------ Giving special tags for each button in order to recognize it later
button.tag = imageButtonTag;
imageButtonTag--;
}
return cell;
}
As you can see, the for loop in my code is in charge of taking the images from my "photosArray" and placing them in the correct button in the cell.
The issue:
The first ~23 buttons get the correct images. Afterwards, (requires to scroll down a bit) starting image 24, the images start repeating. Image 24 is equal to image 0. Image 25 equals image 1 and so on…
I checked many things already. Everything looks fine! I even checked the photosArray indexOfObject and the numbers are correct.
You might think the array is made this way. I thought so too, but i assure you it's fine. I deleted my for loop and instead entered the following code:
//----- select the correct button from the cell
button = (UIButton *)[cell viewWithTag:(1)];
//----- cleaning the button, drawing it's corners, borders and giving it an action
[button setBackgroundImage:nil forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
button.layer.borderWidth = 2;
button.layer.cornerRadius = 5;
button.clipsToBounds = YES;
//------ Setting up the btnImg in order to place on the buttons
UIImage *btnImg = [photosArray objectAtIndex:indexPath.row];
//------ Add btnImg to the button
[button setBackgroundImage:btnImg forState:UIControlStateNormal];
This gives me a tableView with one button in each cell and the buttons get the right images…
One last thing I tried, is this code in my previous code right after creating btnImg:
if ([btnImg isEqual:[photosArray objectAtIndex:0]]) {
NSLog(#"Match found at: %d",[photosArray indexOfObject:btnImg]);
}
But nothing matches (although when i run it i see the images are the same).
This issue is driving me insane for about a week now and i would really appreciate it if someone could help me solve it.
Thanks!
Resetting of view tag is causing it not to be identified. Better way for you to identify each control is through subclassing or some other strategy, especially since you are using tags to get to the control
Related
I have some values of UIButtons. Every button I have created dynamically, by this code:
-(void)AddNewTable: (NSString *) tablePic: (NSString *) addedType {
CreatedTable *ct = [[CreatedTable alloc] init];
CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault);
NSString * uuidString = (__bridge NSString*)CFUUIDCreateString(kCFAllocatorDefault, newUniqueId);
CFRelease(newUniqueId);
UIImage *tableImage = [UIImage imageNamed: tablePic];
CGRect frameBtn = CGRectMake(160.0f, 160.0f, tableImage.size.width, tableImage.size.height);
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage: tableImage forState:UIControlStateNormal];
[button setFrame:frameBtn];
[button addTarget:self action:#selector (draggedOut:withEvent::) forControlEvents:UIControlEventTouchDragInside];
[button setTitle: [NSString stringWithFormat:#"%d", tables.count] forState: UIControlStateNormal];
ct.Id = [uuidString lowercaseString];
ct.posX = 160;
ct.posY = 160;
ct.isActive = true;
ct.Index = button.titleLabel.text;
ct.picture = [NSString stringWithFormat:#"tables/%#", tablePic];
ct.type = addedType;
ct.angle = 0.0;
[tables addObject:ct];
[hallView addSubview:button];
}
CreatedTable - is NSObject with string params of created buttons.
As you can see, I'm adding selector for every created button. I can move every button by this selector. Here is it's code:
- (IBAction)draggedOut: (id)sender withEvent: (UIEvent *) event: (NSSet *)touches {
CreatedTable = [tables objectAtIndex: selected.[titleLabel.text intValue]]
UIButton *selected = (UIButton *)sender;
selected.center = [[[event allTouches] anyObject] locationInView:hallView];
ct.posX = selected.center.x;
ct.posY = selected.center.y; // Here I'm changing params in ct.
}
Now I need to realize multi-select (select some value of buttons by tapping on them, to make some king of a group) and after that I need to move this group (all selected buttons) like one single object.
Any suggestions how to realize it?
When the user select multiple buttons one by one , mark them all the selected buttons by changing their background image . Now when the user starts dragging any one of the selected button create all Bigger view (with the clear background color) and add the copies(new buttons look alike the selected buttons) of all the selected buttons and add them on to the bigger view . Now changing position of original button (button getting dragged) , change the position of bigger view . It will give a look and feel like all the selected button are getting dragged . Also as soon as the bigger view dragging is stopped remove all the original selected buttons from the main view .
Hope it will help you.
you could set a different Tag to each buttons in AddNewTable like this:
[button setTag:];
and then in draggedOut you can find it by:
[sender tag]
I have a UITableView with UITableViewCells that are swipable. When a cell is swiped, I want a view to be visible (revealed) underneath that cell. Here's the code that I have:
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
_cellBack = [[UIView alloc] initWithFrame:CGRectMake(0, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)];
_cellBack.backgroundColor = [UIColor whiteColor];
[self.tableView insertSubview:_cellBack belowSubview:cell];
for (int i = 0; i < [self.tableView subviews].count; i++) {
UIView *v = [[self.tableView subviews] objectAtIndex:i];
if ([v isEqual:_cellBack]) {
NSLog(#"cellBack %d", i);
}
if ([v isEqual:cell]) {
NSLog(#"cell %d", i);
}
}
In the for loop, I check to see if the views' indexes are as I expect, and indeed they are; _cellBack has an index that is one less than cell's index.
When I replace the insertSubview:belowSubview: call with insertSubview:aboveSubview:, it works fine (albeit with the white UIView showing up above the swiped cell), so it's not a matter of not allocating _cellBack properly. I've also tried insertSubview:atIndex: and that didn't work either..
What could be causing this?
Thanks!
To make the SideSwipeTableView example work on ios7 & previous, simply change the line to
[cell.superview insertSubview:self.sideSwipeView belowSubview:cell];
Anything else pushes the back view on top of the cell and you don't get any animation effect, animation happening behind your background cell! To check this change the offset of the cell to less than the full screen to check that your cell is still on the top and background one is really below. From:
cell.frame = CGRectMake(direction == UISwipeGestureRecognizerDirectionRight ? cellFrame.size.width : -cellFrame.size.width, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
to
cell.frame = CGRectMake(direction == UISwipeGestureRecognizerDirectionRight ? cellFrame.size.width/2 : -cellFrame.size.width/2, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
UITableView's already have the ability to put things behind cells. It's the backgroundView of the cell. Why don't you try that instead so you would do the following:
cell.selectedBackgroundView = _cellBack;
So it turns out that, if I add it to another view, the code works as expected.
Here's where I added it:
_cellBack = [[UIView alloc] initWithFrame:CGRectMake(0, cell.contentView.frame.origin.y, cell.frame.size.width, cell.frame.size.height)];
_cellBack.backgroundColor = [UIColor whiteColor];
[cell insertSubview:_cellBack belowSubview:cell.contentView];
I'm still not sure why the code in the question doesn't work. The SideSwipeTableView from this github account has code similar to what I had before and it works fine.
I'm having some trouble getting my buttons to work below a certain y value in my table cells. I'm using a custom UITableViewCell class named "RowWhiskyContent". The default height is 44px and it's below that point my events don't seem to trigger anymore. The button displays just fine and so does everything else below that point, the event however don't seem to trigger. If i place my button half way (like at y=35) only the top part of the button triggers the event and the bottom part doesn't do a thing.
Here's the code trimmed down to the esentials:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
if(![self createView:&cell])
{
UIImage *bottle = [UIImage imageNamed:#"icon_add.png"]; //image size: 22x22
UIButton *bottleButton = [[UIButton alloc] initWithFrame:CGRectMake(60, 70, bottle.size.width, bottle.size.height)];
[bottleButton setImage:bottle forState:UIControlStateNormal];
[cell.contentView addSubview:bottleButton];
[bottleButton addTarget:self action:#selector(addToCollection:) forControlEvents:UIControlEventTouchUpInside];
cell.contentView.frame = CGRectMake(cell.contentView.frame.origin.x, cell.contentView.frame.origin.y, cell.contentView.frame.size.width, 160);
//cell.frame = cell.contentView.frame; // Tried this, didn't work.
//[tableView reloadData]; // Tried this too, didn't work either.
}
return cell;
}
// Check if cell exists and create the cell if it doesn't.
-(BOOL) createView: (UITableViewCell**) cell
{
BOOL cellExists = YES;
*cell = (RowWhiskyContent *) [myTableView dequeueReusableCellWithIdentifier:#"ContentIdentifier"];
if(*cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"RowWhiskyContent" owner:self options:nil];
*cell = [topLevelObjects objectAtIndex:0];
cellExists = NO;
}
return cellExists;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
return 160;
}
Since I'm setting the height of the cell and the contentView both at 160 I'm not sure what's going wrong here. Reloading the data didn't work and neither did setting the cell.frame.
Could anybody please tell me what I'm doing wrong?
Thanks in advance.
EDIT:
Added a screenshot:
Red button works fine but if I place it at the position of the green button it stops working. The contentview's background is set to purple so that explains the purple area. When clicking the cell it triggers the didSelectRowAtIndexPath so I'm guessing the the cell itself is also big enough.
This is definitely a content size issue. Your button will display outside of the frame similar to overflow in CSS, however they will not respond to events. So whatever UIView is containing your UIButton you need to make sure that it's content/frame/bounds are all set tall enough. You can also use [cell.contentView sizeToFit] to adjust it automatically to it's content.
You should definitely NOT reload data inside of the protocol methods for your UITableView.
I cannot get the right way to do the following stuff... (I'm sure I'm not that far but...)
I have a UITableView and within this table I want a particuliar cell to be displayed as a button.
At first I tried to add a button in the cell but I read that was not the right way to do it. Instead it seems better to customize the cell (and make it look like a button). The thing is, I do not really know what subview to change...
What I need:
- no arrow beeing displayed at the right of the cell (I though UITableViewCellAccessoryNone would do the trick... but it did not...).
- the cell to be blue (same blue as the one used when it's clicked)
Below is the code I use:
NSString *section = (NSString *)[sections objectAtIndex:indexPath.section];
NSNumber *row = indexPath.row;
NSString *cellValue = (NSString *)[(NSArray *)[items objectForKey:section] objectAtIndex:row];
cell.textLabel.text = cellValue;
// Make Cell look like a button (used for disconnect option)
if([[sections objectAtIndex:indexPath.section] isEqualToString:#"connection"]) {
cell.textLabel.text = #"Disconnect";
cell.textLabel.textAlignment = UITextAlignmentCenter;
for (UIView* view in cell.contentView.subviews)
{
view.backgroundColor = [UIColor clearColor];
}
cell.accessoryType= UITableViewCellAccessoryNone;
}
Thanks a lot for your help,
Luc
First of all delete the code for cell Accessory view..
and to make it looks like a button, there are several possible solutions . you can make a background image for the cell like button . if you are facing a problem of accessory view that its not hiding , make an image like a button , and set the background image property of cell .
[Cell setBackgroundImage:[UIImage imageNamed:"Yourfilename.png"]];
something like this , if this doesn't work and try adding the image in cell subview ..
[Cell addSubview:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"imagename.png"]]];
this may help !!!
Thanks
Yasir
I have a UITableView with reorderable rows and I'm using the standard UITableViewCell.text property to display text. When I tap Edit, move a row, tap Done, then tap the row, the built-in UILabel turns completely white (text and background) and opaque, and the blue shade to the cell doesn't show behind it. What gives? Is there something I should be doing that I'm not? I have a hacky fix, but I want the real McCoy.
Here is how to reproduce it:
Starting with the standard "Navigation-Based Application" template in the iPhone OS 2.2.1 SDK:
Open RootViewController.m
Uncomment viewDidLoad, and enable the Edit button:
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
Specify that the table has a few cells:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 4;
}
In tableView:cellForRowAtIndexPath:, add a line to set the text property of a cell, and therefore to use the built-in UILabel subview:
// Set up the cell...
cell.text = #"Test";
To enable reordering, uncomment tableView:moveRowAtIndexPath:toIndexPath:. The default implementation is blank, which is fine in this case since the template doesn't include a data model.
Configure the project for the Simulator, OS 2.2.1, Build and Go. When the app comes up, tap Edit, then slide any row to a new position, tap Done, and then tap each row one at a time. Usually a tap will select a row, turn it blue, and turn its text white. But a tap on the row that you just moved does that and leaves the UILabel's background color as white. The result is a confusing white open space with blue strips on the edges. Oddly enough, after the first bogus tap, another tap appears to correct the problem.
So far I have found a hack that fixes it, but I'm not happy with it. It works by ensuring that the built-in UILabel is non-opaque and that it has no background color, immediately upon selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// hacky bugfix: when a row is reordered and then selected, the UILabel displays all crappy
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
for (UIView *view in cell.contentView.subviews) {
if ([[view class] isSubclassOfClass:[UILabel class]]) {
((UILabel *) view).backgroundColor = nil;
view.opaque = NO;
}
}
// regular stuff: only flash the selection, don't leave it blue forever
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
This appears to work, but I don't expect it to be a good idea forever. What is the Right Way to fix this?
This looks like a bug in UITableView's rendering, and you should file a Radar bug report on it. It's like the cells don't get refreshed properly after the move.
One way to work around this for now is to not use the built-in label, but roll your own in the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
CGRect frame = cell.contentView.bounds;
frame.origin.x = frame.origin.x + 10.0f;
UILabel *textLabel = [[UILabel alloc] initWithFrame:frame];
[textLabel setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
textLabel.tag = 1;
textLabel.textAlignment = UITextAlignmentLeft;
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textColor = [UIColor blackColor];
textLabel.font = [UIFont boldSystemFontOfSize:20.0];
textLabel.numberOfLines = 1;
textLabel.highlightedTextColor = [UIColor whiteColor];
[cell.contentView addSubview:textLabel];
[textLabel release];
}
UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
textLabel.text = #"Test";
return cell;
}
I tried this, and it doesn't exhibit the same sort of white blank rectangle you see with the built-in label. However, adding another non-opaque view to the table cell might not be the best for overall rendering performance.
I don't know how major of a glitch this is, because Apple doesn't want you to persist a selection highlight on a table row (they've been enforcing this lately during the review process). You're supposed to place a checkmark or move on to the next level in the navigation hierarchy with a selection, at which point this white box would only be on the screen for a fraction of a second.
The trick in the solution from Brad appears to be:
textLabel.backgroundColor = [UIColor clearColor];
If you leave the background as the default you still get the problem even when you roll your own cells UITableViewCells.
The reason I left it as the default is because the documentation says it is less computationally costly to use opaque backgrounds. Ideally I wouldn't want to use [UIColor clearColor] to fix this bug.
Maybe a completely custom painted cell would somehow fix it. I haven't tried those before though.
Does anyone else have a solution for this?
Thanks for the info, I was searching how to erase the background color from a UILabel.
I used the following line:
textLabel.backgroundColor = [UIColor clearColor];
and worked perfectly!!!
thanks
Alejandra :)
Selections aren't meant to be shown for extended periods! (We got knocked on this for several of our apps)
??? That means Apple would not approve their own Calendar app on iPhone! When you go to edit the start and end times of the event, the start time is selected indefinitely, it only changes once the user taps to the next field.