I have a static cell that stores an information form which user can input fields. One of the static cell is for attachments. I would like to append some UIView into this cell when the user chose an image from the UIImagePickerController. I have already handled the UIImagePickerController part. And I have find the cell by reuseIdentifier:
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"AttachmentCell"];
And I tried to append views in my cell:
CGRect attachmentFrame = CGRectMake(0, 0, 50, 50);
UIView * attachmentRow = [[UIView alloc]initWithFrame: attachmentFrame];
CGFloat ratio = 50 / image.size.width;
CGRect imageFrame = CGRectMake(10, 0, image.size.width * ratio, 50);
CGRect imageNameLabelFrame = CGRectMake(10 + imageFrame.size.width + 10, 22, 300, 6);
UIImageView *imageView = [[UIImageView alloc]initWithFrame: imageFrame];
imageView.image = image;
UILabel *imageNameLabel = [[UILabel alloc]initWithFrame:imageNameLabelFrame];
imageNameLabel.text = [NSString stringWithFormat:#"Attachment %d", attachmentCounter++];
[attachmentRow addSubview: imageView];
[attachmentRow addSubview: imageNameLabel];
attachmentRow.backgroundColor = [UIColor lightGrayColor];
[cell.contentView addSubview: attachmentRow];
NSLog(#"Row appended");
Notice that the above code is just to try adding one single view in the static cell but it seems failed. Nothing shows in my static cell after I add the view. I have logged that my attachment data can successfully brings to this page.
Maybe this is just the wording in the question, but it seems that what you do after the user has selected the image, is that you create a new cell.
This line :
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"AttachmentCell"];
Creates a brand new cell, and your table view has no way to know about it.
What you should rather do is to reload your table view after the user has selected the image and setup it in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In order to reload the data you can use either reloadData method of UITableView which will reload all data or - (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *) withRowAnimation:(UITableViewRowAnimation)animation which will reload only cells at specifed indexes.
firstly add this line
[cell.contentView addSubview: attachmentRow];
then
[attachmentRow addSubview: imageView];
[attachmentRow addSubview: imageNameLabel];
may be it will help
You will have to use custom cell instead of using default tableview cell.
For that first you need to create one with identifier.
Related
Hi i am a newbie to iOS.
I have implemented a tableview in ViewController1.In the tableview i am displaying tittle,detailText and disclosure indicator for the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:MyIdentifier];
}
cell.textLabel.text =[listTableArray objectAtIndex:indexPath.row];
cell.textLabel.textColor=[UIColor grayColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text=#"4mile";
return cell;
}
Everything works fine,Now i need a image before the disclosure indicator when i do it with
UIImageView *accessoryView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
accessoryView.image=[UIImage imageNamed:#"list.png"];
cell.accessoryView = accessoryView;
Disclosure indicator is replaced by the image.But i need both image along with disclosure indicator without using Custom cell.
How can i do it...? Help me out.
Thanks
similiar to the due date but at the place of time i need image
UITableViewCell have a fixed layout, depending on the style you use when you initialize it. You cannot change that layout, since the cell lays out its subviews as it prefers to have them.
add the - (void)layoutSubviews to your cell subclass like this:
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake(0.0f , 0.0f, 20.0f, 20.0f);
}
else try this
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = [UIImage imageNamed:#"list.png"];;
[imageView setFrame:CGRectMake(50, 5, 20, 20)]; // customize the frame
[cell.contentView addSubview:imageView];
If you wanna add UIImageView to standard UITableViewCell you need add your imageView to contentView of cell and add all subviews like a textLabel, detailTextLabel and accessoryView
UIImageView *accessoryImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
accessoryImageView.image=[UIImage imageNamed:#"list.png"];
[cell.contentView addSubview:accessoryImageView];
or subclass of UITableViewCell and implement all views inside it
In my TableViewController I use custom cell, this cell has a scrollView. My cellForRowAtIndexPath method looks like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
// iOS 7 separator
if ([cell respondsToSelector:#selector(setSeparatorInset:)]) {
cell.separatorInset = UIEdgeInsetsZero;
}
}
UIView *subview = [cell viewWithTag:indexPath.row + 1];
if (!subview) {
//... Set up the new cell
[self addScrollViewForCell:cell andCellIndx:indexPath.row];
}
else {
// ... Reuse the cell
}
return cell;
}
If view already exist - I'm trying do not add scrollView. If not - add.
addScrollViewForCell: method:
- (void)addScrollViewForCell: (CustomCell *)tCell andCellIndx:(NSInteger)cIndx {
UIScrollView * myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(5, 62, 350, 61)];
myScrollView.accessibilityActivationPoint = CGPointMake(100, 100);
//Some settings
// ...
UILabel *lblH = [[UILabel alloc] init];
lblH.textAlignment = NSTextAlignmentCenter;
lblH.text = strWeekIdntfr;
lblH.textColor = [UIColor blueColor];
lblH.frame = CGRectMake(offsetScores, 0, cCurrWeekBallsWidth, 15);
[myScrollView addSubview:lblH];
myScrollView.tag = cIndx + 1;
[tCell addSubview:myScrollView];
}
The problem is - when I scroll table to the bottom or to the up, scrollView begin to be added. Checking view by tag I try to differentiate reusable and new one cells, but this didn't work. How Can I solve this?
The reason is because an instance of UITableViewCell is reused when you scroll.
Each time it's being reused, this line UIView *subview = [cell viewWithTag:indexPath.row + 1]; will query for view with different tag. Say, you have 100 cells in this UITableView, a cell might be asked for tag 1, 6, 11, 16, 21 ... 96, which clearly it doesn't have. So it's likely to create a new view every time it's being reused. Multiply this with every cell in the pool and you will get hell load of new scroll views added to them.
To solve this: Just use a fix tag number.
So the line.
UIView *subview = [cell viewWithTag:indexPath.row + 1];
become:
UIView *subview = [cell viewWithTag:1];
And:
myScrollView.tag = cIndx + 1;
become:
myScrollView.tag = 1;
And as #AdamPro13 pointed out, a better and much more elegant way is that you create the scroll view as part of your custom cell. Just put it in initWithFrame:style: of the UITableViewCell's subclass.
The best way that I found it just clear all subview from scrollView. For example like that:
[myCell.scrollView.subviewsmakeObjectsPerformSelector:#selector(removeFromSuperview)];
I have made a custom cell and i want to change the frame of contentView. My cell is a CustomCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"hey");
static NSString *CellIdentifier = #"CustomCellReuseID";
AbcCustomCell *cell = [tabel_Abc dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[AbcCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *name= [arrayTabel_Abc objectAtIndex:indexPath.section];
[cell setBackgroundColor:[UIColor clearColor]];
[cell.label_CellList setText:name];
cell.contentView.frame = CGRectMake (100,0,500,20);
return cell;
}
I have use
cell.contentView.frame = CGRectMake (100,0,500,20);
but its not working for me. I want to change the contentView of customCell, Can any one guide me?? Thanks in advance.
You can't change the contentView. UITableViewCell contentView's height is determined by – tableView:heightForRowAtIndexPath: delegate method and its width is the tableView's width normally.
If you can add a view as subview of contentView and change the view's frame.
You need to re-assign the frame for the cell's contentView.
CGRect oldFrame = cell.contentView.frame;
cell.contentView.frame = CGRectMake( oldFrame.origin.x,
oldFrame.origin.y,
oldFrame.size.width + 20,
oldFrame.size.height );
or you may use custom cell
you can't change the frame of contentView of a cell. you can change the height of a cell by using
tableView:heightForRowAtIndexPath:
But you can't change the width.
Also you can use a view if you want to make as if the divider is big, if you want something like that.
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.contentView.frame.size.width - paddingX*2, 1)];
separatorLineView.backgroundColor = [UIColor redColor];
[cell.contentView addSubview:separatorLineView];
Can you be more specific to which frame you want to change(whether it is out of bounds)?
I have a strange problem using the dequeueReusableCellWithIdentifier: method of UITableView. Not sure if I don't understand the method well enough or is it just plain weird. Here goes:
Im using a UITableView which presents some data to users, and inside my
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath I use the dequeue method like so:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
Afterwards I add some subviews to the contentView property of the cell. When scrolling a bit further down on my table I see those previously added subviews i.e. the cell is not empty but filled with "old" data. If I don't dequeue, and just alloc-init a new one each time, the cells are empty but I do see a bit more memory consumption which is precisely what Im trying to bring down a little. I'm using ARC if that means anything here.
What or how should I tackle the problem? I have tried running a for loop through the subviews of the content view and [view removeFromSuperview] which does remove the previous views and brings down memory consumption a little. But is that really necessary? Or is there a better way?
EDIT here is some more code how I add subviews
cell.backgroundView = [[UIView alloc] initWithFrame:cell.frame];
cell.backgroundColor = kClearColor; //defined to [UIColor clearColor]
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (indexPath.row == 0)
{
UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
shine.image = [UIImage imageNamed:#"top_shine_1"];
[cell.backgroundView addSubview:shine]; //its a gradient thats why its added to background
UILabel *appLabel = [[UILabel alloc] initWithFrame:CGRectMake(55, winSize.height * 0.027, 250, 33)];
appLabel.backgroundColor = kClearColor; //defined to clear color
appLabel.textColor = kWhiteColor; //defined to white color
appLabel.text = [viewOrder objectAtIndex:tableView.tag]; //just an array from where I get the required text
appLabel.font = kStandardFontOfSize(30); //defined to a specific font
[cell.contentView addSubview:appLabel];
UIButton *settingsButton = [UIButton buttonWithType:UIButtonTypeCustom];
settingsButton.frame = CGRectMake(10, winSize.height * 0.0377, 31, 21);
[settingsButton setImage:[UIImage imageNamed:#"settings_button"] forState:UIControlStateNormal];
[settingsButton addTarget:self action:#selector(settings:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:settingsButton];
return cell; //here I just return it since this is all the config the first cell needs
}
NSString *app = [viewOrder objectAtIndex:tableView.tag];
NSArray *boxes = [[plist secondObjectForKey:#"order" parent:app] componentsSeparatedByString:#";"];
//Add necessary shines or create the last logotype cell - just some details and stuff, all are just images
if (indexPath.row == 1)
{
UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 282.5)];
shine.image = [UIImage imageNamed:#"top_shine_2"];
[cell.backgroundView addSubview:shine];
}
else if (indexPath.row == 2)
{
UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, winSize.width, 150)];
shine.image = [UIImage imageNamed:#"main_shine"];
[cell.backgroundView addSubview:shine];
}
else if (indexPath.row == boxes.count + 1)
{
UIImageView *logo = [[UIImageView alloc] initWithFrame:CGRectMake(111.5, 25, 97, 20)];
logo.image = [UIImage imageNamed:#"cell_logo"];
[cell.backgroundView addSubview:logo];
return cell;
}
NSString *databox = [boxes objectAtIndex:indexPath.row - 1];
UIView *view; //Main subview to be added to the cell
/*
here I have a class that creates a view with a bunch of subviews added to that view, the view is then assigned to 'view'; kinda like
view = [someAssembler assembleViewWith:options.....]. all are basically UILabels or ImageViews added to the main view
*/
[cell.contentView addSubview:view]; //and here this 'main view' is added as a subview, this view is still visible after the cell has been dequeued and the shines are as well
return cell;
Before you start criticising why im not using a single UIColor for background and text color let me remind you that this is still in testing stage, it will be taken care of later.
[cell.backgroundView addSubview:shine]; these lines of code are the problem in your case.
You should create a complete reusable cell within the if (!cell) block and repopulate them each time cellForRow is being called. For every unique cell a unique reuse identifier should be used. For example, if you have multiple cells with differently laid out subviews, you should use different identifiers for them.
In your specific example cells must be created in the if (indexPath.row == 1) blocks.
static NSString *cellIdentifier = #"cell";
UITableViewCell *cell = nil;
if (indexPath.row == 0) {
cellIdentifier = #"topCell";
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
if (!cell) {
// create the cell and add the necessary subviews for indexPath row 0
}
return cell;
}
else if (indexPath.row == 1) {
}
//etc.
}
You'll have to create the "main subview" for each cell in the !cell block with this approach though, so you should probably look into subclassing a cell.
i have a TableView with custom table cells. I add programmatically borders at the bottom of each cell to keep the screendesign layout. Everything is fine, when the App loads the first time. But after scrolling (and scrolling back to the top) multiple border lines are displayed all over the screen.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *CellIdentifier = #"CellProgramm";
ProgrammTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
...
if([object.cellMessageArray[1] isEqualToString:#"wrapper"] || [object.cellMessageArray[1] isEqualToString:#"keynote"] || [object.cellMessageArray[1] isEqualToString:#"break"]) {
UIImageView *lineSeparator = [[UIImageView alloc] initWithFrame:CGRectMake(0, cell.bounds.size.height, 1024, 5)];
lineSeparator.image = [UIImage imageNamed:[NSString stringWithFormat:#"blind.png" ]];
lineSeparator.backgroundColor = [UIColor whiteColor];
[cell.contentView addSubview:lineSeparator];
}
else if([object.cellMessageArray[1] isEqualToString:#"standard"]) {
UIImageView *lineSeparator = [[UIImageView alloc] initWithFrame:CGRectMake(60, cell.bounds.size.height+4, 1024, 1)];
lineSeparator.image = [UIImage imageNamed:[NSString stringWithFormat:#"blind.png" ]];
lineSeparator.backgroundColor = [UIColor pxColorWithHexValue:#"eeeeee"];
[cell.contentView addSubview:lineSeparator];
}
}
Has anyone an idea?
When you scroll a tableview, the cells are reused (dequeueReusableCellWithIdentifier) to optimize performance. In the code above, a lineSeparator image view is added to the cell each time the cellForRowAtIndexPath method is invoked. If the cell is used 5 times, it will have 5 image views added.
One way address this is to remove the lineSeparator image view from the cell before it is reused. This is typically done in the cell's prepareForReuse method.
In the cellForRowAtIndexPath, add a tag to the lineSeparator image view (e.g., lineSeparator.tag = 100;
In your cell's class, implement the prepareForReuse method. E.g.:
-(void)prepareForReuse{
UIView *lineSeparatorView = [self.contentView viewWithTag:100];
[lineSeparatorView removeFromSuperview];
}