How to call didSelectRowAtIndexPath from subclassed UITableViewCell - ios

I have a UITableView that I am using to show data that requiers me to have a much wider cell than the iPhone screenWidth.
Because of this I have created a subclassed UITableViewCell that contains a subclassed UIScrollView. This is what my code looks like.
TableView.h
#property (strong, nonatomic) CustomCell *cell;
TableView.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cellDictionary = [xmlMArray objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.itemsDictionary = cellDictionary;
cell.currentIndex = indexPath;
cellDictionary = nil;
[cell drawCell];
return cell;
}
In the above method you can see I am calling a custom UITableViewCell that I have created.
CustomCell.h
#property (strong, nonatomic) NSDictionary *itemsDictionary;
#property (strong, nonatomic) MyScrollView *scrollCell;
#property (strong, nonatomic) NSIndexPath *currentIndex;
- (void)drawCell;
CustomCell.m
- (void)drawCell
{
scrollCell = [[MyScrollView alloc] init];
scrollCell.itemsDictionary = itemsDictionary;
[scrollCell drawCell];
scrollCell.backgroundColor = [UIColor whiteColor];
scrollCell.frame = CGRectMake(0.0, 0.0, ScreenWidth, 45.0);
[[self contentView] addSubview:scrollCell];
}
In the above drawCell method I am calling a custom scrollView
MyScrollView.m
- (void)drawCell
{
bgGray = NO;
fNameString = [[UILabel alloc] init];
fNameString.backgroundColor = [UIColor clearColor];
fNameString.frame = CGRectMake(15.0, 0.5, 70.0, 40.0);
fNameString.text = [itemsDictionary objectForKey:#"fName"];
lNameString = [[UILabel alloc] init];
lNameString.backgroundColor = [UIColor clearColor];
lNameString.frame = CGRectMake(105.0, 0.5, 95.0, 40.0);
lNameString.text = [itemsDictionary objectForKey:#"lName"];
addressString = [[UILabel alloc] init];
addressString.backgroundColor = [UIColor clearColor];
addressString.frame = CGRectMake(220.0, 10.5, addressString.frame.size.width, 50.0);
addressString.text = [NSString stringWithFormat:#"Address: %#: %#",[itemsDictionary objectForKey:#"aNumber"] ,[itemsDictionary objectForKey:#"aString"]];
[addressString sizeToFit];
[self setContentSize:(CGSizeMake((220.0 + addressString.frame.size.width)+15, 45.0))];
[self addSubview:fNameString];
[self addSubview:lNameString];
[self addSubview:addressString];
}
The above method draws the scrollview that is then passed onto the CustomCell, everything works fine and displays correctly, below is the method I am using to detect a touch on the cusome scroll view its in the same class as the method above and looks like this.
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
NSLog(#"touch scroll");
// If not dragging, send event to next responder
if (!self.dragging) {
// touch detected...
//How can I now call didSelectRow from TableView?
} else {
[super touchesEnded: touches withEvent: event];
}
}
So my question is this, how can I use this touchEnded method to call didSelectRowFromIndexPath method that is in the original TableView class? Or is there a better way to do this than what I am currently doing?
Note: the reason I have had to use these subclasses is because the UIScrollView is covering the UITableViewCell selection function, so I had to subclass the scrollview to intercept the touch event now I'm hoping I can call the original tableview selection method with your help.

How about calling the delegate function using the following code:
[yourTableView.delegate tableView:tableView didSelectRowAtIndexPath:aIndexPath];
In your subclassed cell store a weak reference to your tableview and indexPath.
Another solution is to loop through your cell's superview until you find the tableview. This has its cons though, Apple may one day change the way the view hierarchy structured which will break the code as they did from iOS6 to iOS7 by wrapping another layer around some views...

Related

UICollectionview is not working, I am not getting any Cell

I am trying to use a collection view and reuse a collection view cell and I have to get 23 images and name from server which I have not started coz of the problem I am facing
This is my custom cell file collection view file objective c
Below is my custom cell.h
#import <UIKit/UIKit.h>
#interface CustomCell : UICollectionViewCell
{
UIImageView *imageView;
}
#property (nonatomic, retain) UIImageView *imageView; //this imageview is the only thing we need right now.
#end
Here is my custom cell.m file
#import "CustomCell.h"
#implementation CustomCell
#synthesize imageView;
- (id)initWithFrame:(CGRect)aRect
{
if (self = [super initWithFrame:aRect])
{
//we create the UIImageView in this overwritten init so that we always have it at hand.
imageView = [[UIImageView alloc] init];
//set specs and special wants for the imageView here.
[self addSubview:imageView]; //the only place we want to do this addSubview: is here!
//You wanted the imageView to react to touches and gestures. We can do that here too.
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onButtonTapped:)];
[tap setNumberOfTapsRequired:1];
[self addGestureRecognizer:tap];
//We can also prepare views with additional contents here!
//just add more labels/views/whatever you want.
}
return self;
}
-(void)onButtonTapped:(id)sender
{
//the response to the gesture.
//mind that this is done in the cell. If you don't want things to happen from this cell.
//then you can still activate this the way you did in your question.
}
#end
These are the methods in my normal view controller.m file
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cvCell" forIndexPath:indexPath];
[[[cell contentView] subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
// create a uiview where we can place all views that need to go into this cell
UIView * contents=[[UIView alloc] initWithFrame:cell.contentView.bounds];
[contents setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:contents];
// set tag to the indexPath.row so we can access it later
[cell setTag:indexPath.row];
// add interactivity
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onButtonTapped:)];
[tap setNumberOfTapsRequired:1];
[cell addGestureRecognizer:tap];
if (cell.selected) {
cell.backgroundColor = [UIColor blueColor]; // highlight selection
}
else
{
cell.backgroundColor = [UIColor redColor]; // Default color
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor blueColor]; // highlight selection
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor redColor]; // Default color
}
I don't get any cell when I moved to this view, it is just blank with the background image and I have even given a blank picture to see how the view is but I don't get anything please help!!!
The cells are not displaying because you might not have set the datasource and delegate properly.
Since you have added the cells in storyboard you don't need to add the imageview as subview in the collection view cell.
First connect the outlet of imageview that you have added in storyboard to the CustomCell. Then remove
{
UIImageView *imageView;
}
#property (nonatomic, retain) UIImageView *imageView;
You can remove - (id)initWithFrame:(CGRect)aRect this method and you can add the tap gesture initialization in awakeFromNib method
-(void)awakeFromNib {
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onButtonTapped:)];
[tap setNumberOfTapsRequired:1];
[self addGestureRecognizer:tap];
}
No need to do
imageView = [[UIImageView alloc] init];
[self addSubview:imageView];
Again in cellForItemAtIndexPath
remove the following lines
[[[cell contentView] subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView * contents=[[UIView alloc] initWithFrame:cell.contentView.bounds];
[contents setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:contents];
After making these changes please try again

UITableView after prepareForReuse - all the data in Cell disappear

I have a TableView with customCell, that has next properties:
#interface CustomTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *image;
#property (weak, nonatomic) IBOutlet UILabel *nameOfImage;
#property (weak, nonatomic) IBOutlet UIButton *start;
#property (weak, nonatomic) IBOutlet UIButton *stop;
#property (weak, nonatomic) IBOutlet UIProgressView *progressView;
#property (weak, nonatomic) IBOutlet UILabel *realProgressStatus;
In table view - when user press start button - an image is downloaded, as well as progressView with realProgressStatus reflects current situation. At this stage everything works perfect, but when scroll table view and return back to the cell - that was already fulfilled with data - all info disappeared(except the nameOfImage, I set it separately).
I implemented next method in my CustomTableViewCell class:
-(void)prepareForReuse
{
[super prepareForReuse];
self.progressView.progress = 0.1;
self.realProgressStatus.text = #"";
self.image.image = [UIImage imageNamed:#"placeholder"];
}
I implemented new property NSMutableSet self.tagsOfCells, where I save number of cells where images where already downloaded.
I tried to make changes in TableView method but effect is the same :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* PlaceholderCellIdentifier = #"Cell";
CustomTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier forIndexPath:indexPath];
customCell.delegate = self;
customCell.cellIndex = indexPath.row;
if (!customCell)
{
customCell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
}
else
{
NSNumber *myNum = [NSNumber numberWithInteger:indexPath.row];
if (![self.tagsOfCells containsObject:myNum])
{
NSLog(#"Row: %ld",(long)indexPath.row);
UIImage *img = [UIImage imageNamed:#"placeholder"];
customCell.realProgressStatus.text = #"";
customCell.progressView.progress = 0.1;
customCell.image.image = img;
[customCell setNeedsLayout];
}
}
if ( indexPath.row % 2 == 0 )
customCell.backgroundColor = [UIColor grayColor];
else
customCell.backgroundColor = [UIColor darkGrayColor];
customCell.nameOfImage.text = self.names[indexPath.row];
return customCell;
}
EDIT:
I populate self.tagsOfCells in one of methods during downloading images, here is the method:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.customCell.realProgressStatus.text = #"Downloaded";
UIImage *img = [UIImage imageWithData:self.imageData];
self.customCell.image.image = img;
self.customCell.tag = self.selectedCell;
[self.savedImages setObject:img forKey:self.customCell.nameOfImage.text];
NSNumber *myNum = [NSNumber numberWithInteger:self.selectedCell];
[self.tagsOfCells addObject:myNum];
}
Thanks in advance for any help or advice.
Content-related actions shouldn't occur in the prepareForReuse function.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewCell_Class/#//apple_ref/occ/instm/UITableViewCell/prepareForReuse
If a UITableViewCell object is reusable—that is, it has a reuse identifier—this method is invoked just before the object is returned from the UITableView method dequeueReusableCellWithIdentifier:. For performance reasons, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state. The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell. If the cell object does not have an associated reuse identifier, this method is not called. If you override this method, you must be sure to invoke the superclass implementation.
Edited
Alfie is right, prepareForReuse isn't invoked after returning from cellForRowAtIndexPath
First thing I would try is edit the code
if (!customCell)
{
customCell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
}
else
{
NSNumber *myNum = [NSNumber numberWithInteger:indexPath.row];
if (![self.tagsOfCells containsObject:myNum])
{
NSLog(#"Row: %ld",(long)indexPath.row);
UIImage *img = [UIImage imageNamed:#"placeholder"];
customCell.realProgressStatus.text = #"";
customCell.progressView.progress = 0.1;
customCell.image.image = img;
[customCell setNeedsLayout];
}
}
to the following
if (!customCell)
{
customCell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
}
NSNumber *myNum = [NSNumber numberWithInteger:indexPath.row];
if (![self.tagsOfCells containsObject:myNum])
{
NSLog(#"Row: %ld",(long)indexPath.row);
UIImage *img = [UIImage imageNamed:#"placeholder"];
customCell.realProgressStatus.text = #"";
customCell.progressView.progress = 0.1;
customCell.image.image = img;
[customCell setNeedsLayout];
}
This really isn't an expensive operation and it's better to have this logic in a single place. Especially since you got rid of prepareForReuse, this should be changed.
The reason when you scroll away, and then come back to not find your data is cellForRowAtIndexPath is being called again, which results in the default data overriding the new data you just added.
You would want to have an underlying data structure and retrieve data from there.
What I would do:
For instances, you can keep a mutable list as such
NSMutableArray* tableData = [[NSMutableArray alloc] init];
add image data for each row to the array
[tableData add:imageData];
and then display it add cellForRowAtIndexPath
customCell.image.image = [tableData objectAtIndex:[indexPath row]];
This would be the normal practice for populating a UITableView with data. This way, even if you scroll away tableData would remain the same, resulting in consistent data.
Note
I would also call new data asynchronously using NSURLSession from within the cell if I had to implement this. Just a suggestion=)
I don't think this has anything to do with your use of prepareForReuse. A couple things look fishy.
You're setting the delegate and cellIndex properties on your cell before you know whether it's nil or not. If it's nil then these properties will never be set.
I also don't think you need the else clause in there. The logic that it wraps doesn't have anything to do with whether a cell could be dequeued. it has to do with configuring a non-nil cell.
A missing piece from your question is where do you populate the tagsOfCells object? That code is important. If you're not setting the tag in cellForRowAtIndexPath it seems like your data will get out of sync and this will cause your cell to be misconfigured.
Try the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* PlaceholderCellIdentifier = #"Cell";
CustomTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier forIndexPath:indexPath];
if (!customCell)
{
customCell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
}
NSNumber *myNum = [NSNumber numberWithInteger:indexPath.row];
if (![self.tagsOfCells containsObject:myNum])
{
NSLog(#"Row: %ld",(long)indexPath.row);
UIImage *img = [UIImage imageNamed:#"placeholder"];
customCell.realProgressStatus.text = #"";
customCell.progressView.progress = 0.1;
customCell.image.image = img;
[customCell setNeedsLayout];
}
customCell.delegate = self;
customCell.cellIndex = indexPath.row;
customCell.nameOfImage.text = self.names[indexPath.row];
if (indexPath.row % 2 == 0)
{
customCell.backgroundColor = [UIColor grayColor];
}
else
{
customCell.backgroundColor = [UIColor darkGrayColor];
}
return customCell;
}
Edit
Regarding info in another answer here. prepareForReuse is not being called after you configure your cell. It's being called when you invoke dequeueReusableCell and hence before you configure your cell. I don't believe prepareForReuse is the problem.
It looks like you are not using interface builder's prototype cells so you are using the wrong dequeue reusable cell method. The correct one in your situation does not have an index path param e.g.
CustomTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
And as the others said you need to move your 2 lines of initialization after you alloc init your custom cell because it's nil before then. Eg you need to dequeue the cell and if nil create one. Then set your params on the cell now you have a valid instance.

Objective C - Swipe to delete triggers button in tableview cell

I have a tableview where the user can edit the cell content by tapping the cell using a button. When I use the swipe to delete function the 'edit button' gets triggered and causes the app to crash. How can I make shure other buttons in the cell are disabled when I 'swipe to delete'?
EDIT: example code added.
CustomCell.h:
#interface CustumCell : UITableViewCell {
UILabel *cellText;
UIButton *editButton;
}
#property (nonatomic,retain) UILabel *cellText;
#property (nonatomic,retain) UIButton *editButton;
#end
CustomCell.m:
#implementation CustumCell
#synthesize cellText,editButton;
- (void)awakeFromNib {
self.backgroundColor = [UIColor clearColor];
cellText = [[UILabel alloc] init];
cellText.translatesAutoresizingMaskIntoConstraints=NO;
[self.contentView addSubview:cellText];
//Cell Constraints
NSArray *verticalConstraintsCell =
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-6-[cellText(>=31)]"
options: 0
metrics:nil
views:NSDictionaryOfVariableBindings(cellText)];
NSArray *horizontalConstraintsCell =
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-15-[cellText(>=2)]-50-|"
options: 0
metrics:nil
views:NSDictionaryOfVariableBindings(cellText)];
[self.contentView addConstraints:verticalConstraintsCell];
[self.contentView addConstraints:horizontalConstraintsCell];
editButton = [[UIButton alloc] init];
[self.contentView addSubview:editButton];
}
TableViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustumCell *cell= (CustumCell *)[tableView dequeueReusableCellWithIdentifier:#"CellSection1" forIndexPath:indexPath];
if (cell==nil) {cell = [[CustumCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellSection1"];}
// add cell content..
//frame editButton:
cell.editButton.frame= CGRectMake(tableView.frame.size.width/2, 0, tableView.frame.size.width/2-50, 43);
[cell.editButton addTarget:self action:#selector(editButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
Now when I swipe to delete, the 'editButtonPressed' function executes.
Thanks.
It sounds like you are creating your button in code and adding it directly as a subview of the cell. This will cause the behavior you're seeing.
When subclassing a UITableViewCell or UICollectionView cell you should not add views directly as subviews of self. Instead, you must add them as subviews of self.contentView.

iOS - sub views of UITableviewCell do not reload/update

I've got a table view where the cells are created as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = #"TempTitle";
cell.textLabel.font = [UIFont fontWithName: #"AppleSDGothicNeo-Bold" size:16.0];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UILabel *numberLabel = [[UILabel alloc] init];
[numberLabel setFrame:CGRectMake(230.0, 5.0, 40.0, 30.0)];
[numberLabel setText:[NSString stringWithFormat:#"%#", [self.arrayOne objectAtIndex:indexPath.row]]];
UIButton *buttonDown = [[UIButton alloc] init];
[buttonDown setFrame:CGRectMake(190.0, 5.0, 40.0, 30.0)];
buttonDown.tag = indexPath.row;
[buttonDown addTarget:self action:#selector(quantityDown:) forControlEvents:UIControlEventTouchUpInside];
UIButton *buttonUp = [[UIButton alloc] init];
[buttonUp setFrame:CGRectMake(270.0, 5.0, 40.0, 30.0)];
[cell addSubview:buttonDown];
[cell addSubview:numberLabel];
[cell addSubview:buttonUp];
return cell;
}
where self.arrayOne (name changed for this thread) holds integer values that are displayed in each cell. The method when buttonDown is selected is as following:
- (void) quantityDown:(id)sender {
int clicked = ((UIButton *)sender).tag;
... math to lower int by one and save the new value in arrayOne
... this part works just fine. The value does go down, as intended.
[self.tableView reloadData];
}
When the tableView reloads, a new label is printed on top of the existing label in that cell, as can be seen in the image below:
I can only assume that new buttons are being printed on top of the existing ones as well. This is both expensive and makes the numbers unreadable (especially if you change it multiple times!). Leaving the view and coming back to it shows the new numbers cleanly, but only until you start changing them again.
A similar effect happens when I use the UISegmentedControl at the top. Selecting one or the other changes the contents of the table and runs [self.tableView reloadData]. The textLabel for each cell reloads just fine when this method is called, but the sub views do not reload, and instead stack upon one another.
How would I go about writing this so that there is only ever one subview in each cell, instead of multiple stacked upon one another? Something speedy and not expensive on resources. Maybe removing all subviews and then adding the new ones? I tried something like
[[cell.contentView viewWithTag:tagVariable]removeFromSuperview];
to no avail. Really, I only need to modify the one cell in the table that the user is clicking in. Except for when the user uses the UISegmentedControl at the top, then all the cells need to be modified.
Thanks in advance.
EDIT 1:
Created a custom UITableViewCell class...
#interface SSCustomTableViewCell : UITableViewCell
#property (nonatomic) UILabel *quantity;
#property (nonatomic) UIButton *down;
#property (nonatomic) UIButton *up;
#end
#implementation SSWeightsTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.quantity = [UILabel new];
[self.contentView addSubview:self.quantity];
self.down = [UIButton new];
[self.contentView addSubview:self.down];
self.up = [UIButton new];
[self.contentView addSubview:self.up];
}
return self;
}
- (void) layoutSubviews {
[super layoutSubviews];
[self.down setFrame:CGRectMake(190.0, 5.0, 40.0, 30.0)];
[self.down setBackgroundColor:[UIColor purpleColor]];
[self.up setFrame:CGRectMake(270.0, 5.0, 40.0, 30.0)];
[self.up setBackgroundColor:[UIColor purpleColor]];
[self.quantity setFrame:CGRectMake(230.0, 5.0, 40.0, 30.0)];
[self.quantity setTintColor:[UIColor purpleColor]];
}
#end
and then in my UITableView class...
#import "SSCustomTableViewCell.h"
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView
registerClass:[SSCustomTableViewCell class]
forCellReuseIdentifier:NSStringFromClass([SSCustomTableViewCell class])
];
}
and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier: NSStringFromClass([SSWeightsTableViewCell class])
forIndexPath:indexPath
];
}
but now all I see is the following...
where the subviews are not correctly laid out, nor are they the correct size. Also, within the cellForRowAtIndexPath method, I cannot access the cell's components. When I enter
cell.quantity
I get an error saying that "Property 'quantity' not found on object of type UITableViewCell*"
So I tried
SSCustomTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier: NSStringFromClass([SSWeightsTableViewCell class])
forIndexPath:indexPath
];
and the error goes away, but it still looks the same when I run it.
Edit 2: Working Solution
All I had to do was add
cell = [[UITableViewCell alloc]init];
within the cellForRowAtIndexPath method. Everything else stayed the same, and no custom classes required.
You are seeing this error because cell instances are reused. If you add a view each time you configure the cell, you will be adding to cells that already have the subviews on them. You should create your own subclass of UITableViewCell and add the subviews to it in init. Then your method above would just set the values on the various subviews.
Your cell would look something like this:
#interface MyCustomCell : UITableViewCell
#property (nonatomic, strong) UILabel *myCustomLabel;
#end
#implementation MyCustomCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.myCustomLabel = [UILabel new];
[self.contentView addSubview:self.myCustomLabel];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Arrange self.myCustomLabel how you want
}
#end
Then your view controller would look like this:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView
registerClass:[MyCustomCell class]
forCellReuseIdentifier:NSStringFromClass([MyCustomCell class])
];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:NSStringFromClass([MyCustomCell class])
forIndexPath:indexPath
];
cell.myCustomLabel.text = #"blah";
return cell;
}
Try this in cell configure method, this will make sure objects doesn't overlap
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellId = #"cellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell==nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
return cell;
}
Hope this will help

I can't make corners of images and buttons rounded

I'm creating the cells of a UITableViewController.
In one of them, a small image is contained. I tried the following to make its corners rounded:
profileImage.layer.cornerRadius = 8;
profileImage.clipsToBounds = YES;
In another cell prototype, I tried to make the corners of a button rounded:
chooseImageFromRoll.clipsToBounds = YES;
chooseImageFromRoll.layer.cornerRadius = 8;
In both cases I included
#import <QuartzCore/QuartzCore.h>
The button and the image whose corners must be rounded are property of the UITableViewController owning them:
#import <UIKit/UIKit.h>
#interface profileRegistrationCellVC : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *profileImage;
#property (weak, nonatomic) IBOutlet UIButton *chooseImageFromRoll;
#property (weak, nonatomic) IBOutlet UIButton *shootImage;
#end
In relative .m class:
#import "profileRegistrationCellVC.h"
#import <QuartzCore/QuartzCore.h>
#implementation profileRegistrationCellVC
#synthesize profileImage;
#synthesize chooseImageFromRoll;
#synthesize shootImage;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
chooseImageFromRoll.clipsToBounds = YES;
chooseImageFromRoll.layer.cornerRadius = 8;
shootImage.layer.cornerRadius = 8;
profileImage.layer.cornerRadius = 8;
profileImage.clipsToBounds = YES;
profileImage.layer.borderColor = [UIColor whiteColor].CGColor;
profileImage.layer.borderWidth = 20.0;
[self addSubview:profileImage];
[self addSubview:chooseImageFromRoll];
[self addSubview:shootImage];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
Here's the code of my function cellForRowAtIndexPath, in my uitableviewcontroller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
static NSString *CellIdentifier = #"profileRegistrationCell";
profileRegistrationCellVC *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[profileRegistrationCellVC alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//cell.profileImage.image.layer.masksToBounds = YES;
//cell.profileImage.layer.cornerRadius = 5.0;
return cell;
}
else if (indexPath.section == 1) {
static NSString *CellIdentifier = #"regularRegistrationCell";
regularRegistrationCellVC *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[regularRegistrationCellVC alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.regularFieldName.text = [_registrationItems objectAtIndex:indexPath.row];
if ([[_registrationItems objectAtIndex:indexPath.row] isEqualToString:#"Email*"])
cell.regularTextField.keyboardType = UIKeyboardTypeEmailAddress;
if ([[_registrationItems objectAtIndex:indexPath.row] isEqualToString:#"Età"]) {
cell.regularTextField.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
}
return cell;
}
else{
static NSString *CellIdentifier = #"orientationRegistrationCell";
orientationRegistrationCellVC *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[orientationRegistrationCellVC alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.fieldLabel.text = [_registrationItems objectAtIndex:[_registrationItems count]-1];
cell.orientationLabel.text = #"Non specificato";
return cell;
}
}
But in no case I managed to make corners rounded. Can you tell where I'm mistaking?
Thanks
The code snippets above are both correct and have no issues. My assumption is that your issue lies elsewhere in creating the button that contains the image. The following code will create a button and will round it's corners, also I added the border to it in case you want to add that too. You can plug in the image you have in there as well. I have added a image of what this code will create for your reffrence also. Hope it will help you out.
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 100, 100,50);
[btn setTitle:#"Hello" forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor colorWithRed:128.0/255.0f green:0.0/255.0f blue:0.0/255.0f alpha:0.7]];
btn.frame = CGRectMake(100.0, 100.0, 120.0, 50.0);//width and height should be same value
btn.clipsToBounds = YES;
btn.layer.cornerRadius = 20;//half of the width
btn.layer.borderColor=[UIColor redColor].CGColor;
btn.layer.borderWidth=2.0f;
[self.view addSubview:btn];
Below is the image of the button that is related with the above code
Edit:
another way of doing the round corners is to use the method masksToBounds here is an example of it within the generic cell right out of the box from the template.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDate *object = _objects[indexPath.row];
cell.textLabel.text = [object description];
cell.imageView.image = [UIImage imageNamed:#"acolon.png"];
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = 5.0;
return cell;
}
here is the screen shot of the result:
i know you using a custom cell, so implement the maskToBount in the cellForRowAtImdexPath or wherever you are populating the tableview with its custom cells.

Resources