I need to make cell selectionBackgroundView not on full width in plain UItableView. For this I made UItableViewCell subclass and override layoutsubviews method
- (void)layoutSubviews
{
[super layoutSubviews];
self.selectedBackgroundView.frame = CGRectMake(self.frame.origin.x + 10.0f, self.frame.origin.y, self.frame.size.width - 20.0f, self.frame.size.height);
}
My cellForRowAtIndexPath method looks like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [NSString stringWithFormat: #"CELL %i %i", indexPath.section, indexPath.row];
GroupedTableCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if(cell == nil)
{
cell = [[GroupedTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
UIView *cellBgView = [[UIView alloc] init];
cellBgView.frame = CGRectMake(10, 0, 300, 80);
[cellBgView setBackgroundColor:[UIColor colorWithRed:242 / 255.0 green:242 / 255.0 blue:242 / 255.0 alpha:1.0]];
[cell.contentView addSubview:cellBgView];
}
[cell setBackgroundColor:[UIColor clearColor]];
UIView *selectionView = [[UIView alloc] init];
[selectionView setBackgroundColor:[UIColor colorWithRed:181 / 255.0 green:211 / 255.0 blue:53 / 255.0 alpha:1.0]];
selectionView.frame = CGRectMake(10, 0, 300, 80);
cell.selectedBackgroundView = selectionView;
return cell;
}
But only for first row selectedView works correct. For other rows I have selectedView with clear color. Please, help me.
All I need was to set frame with numbers.
- (void)layoutSubviews
{
[super layoutSubviews];
self.selectedBackgroundView.frame = CGRectMake(10.0f, 0, 300, 80);
}
Instead add the background in the subclassed cell itself,
do like this it is an example how you can manage the selection and deselection state in the cell change it to your requirements
//in your subclassed cell
#import "GroupedTableCell.h"
#implementation GroupedTableCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
//add the background view hear only, changes the frame in the layoutsubviews
UIView *cellBgView = [[UIView alloc] init];
[cellBgView setTag:12345];//using tag to access in the layoutsubviews
[self addSubview:cellBgView];//hear u added the background view
}
return self;
}
//manage the cell selection and deselection state hear
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
// Configure the view for the selected state
[super setSelected:selected animated:animated];
UIView *cellBgView = [self viewWithTag:12345];
if(selected)
{
[cellBgView setBackgroundColor:[UIColor colorWithRed:242 / 255.0 green:242 / 255.0 blue:242 / 255.0
alpha:1.0]]; //your selected background color
}
else
{
[cellBgView setBackgroundColor:[UIColor clearColor]]; //your deselected background color
}
}
//setting the frames of views within the cell
- (void)layoutSubviews
{
[super layoutSubviews];
UIView *cellBgView = [self viewWithTag:12345];
cellBgView.frame = CGRectMake(10, 0, 300, 80);//always set the frame in layoutSubviews
}
in your controller just do like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GroupedTableCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[GroupedTableCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
return cell;
}
Hope this helps u :)
Related
I am trying to create expand/collapse cell. On every cell, it has subview of UIView for border bottom. If expanded, the border should also go to bottom of the cell. It is working fine on initial load of the cells, however, when I scroll down, the border is no longer going to the bottom.
I am adjusting the border originY via taskOptionsExpand method. That method is getting the border view via [cell.contentView viewWithTag:2].
Code below:
#import "HomeViewController.h"
#interface HomeViewController ()<UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) UITableView *tableView;
#property (strong, nonatomic) NSIndexPath *selectedIndexPath;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.selectedIndexPath = nil;
[self.view addSubview:self.tableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (UITableView *)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc] init];
_tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[_tableView addSubview:self.tableRefreshControl];
}
return _tableView;
}
# pragma mark - table view delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 100;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.selectedIndexPath isEqual:indexPath]) {
return 80;
}else{
return 50;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// text view
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width-20, 50)];
view1.backgroundColor = [UIColor clearColor];
view1.tag = 0;
UILabel *title = [[UILabel alloc] initWithFrame:view1.frame];
title.text = #"Lorem ipsum";
title.textColor = [UIColor grayColor];
[view1 addSubview:title];
// options view
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
view2.backgroundColor = [UIColor orangeColor];
view2.tag = 1;
// border bottom
CGRect frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
if ([self.selectedIndexPath isEqual:indexPath]) {
frame.origin.y = 79; //expand
} else {
}
UIView *border = [[UIView alloc] initWithFrame:frame];
border.backgroundColor = [UIColor blueColor];
border.tag = 2;
cell.clipsToBounds = YES;
[cell.contentView addSubview:view1];
[cell.contentView addSubview:view2];
[cell.contentView addSubview:border];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.selectedIndexPath isEqual:indexPath]) {
[self taskOptionsExpand:NO indexPath:indexPath];
self.selectedIndexPath = nil;
} else {
[self taskOptionsExpand:YES indexPath:indexPath];
[self taskOptionsExpand:NO indexPath:self.selectedIndexPath];
self.selectedIndexPath = indexPath;
}
[tableView beginUpdates];
[tableView endUpdates];
}
- (void) taskOptionsExpand:(BOOL) expand indexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIView *border = [cell.contentView viewWithTag:2];
NSLog(#"border: %#", border);
if (expand) {
border.frame = CGRectMake(20, 79, self.view.frame.size.width-40, 1);
}else{
border.frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
}
}
#end
When scrolling the table view, the cell is dequeued to get reusable cell and as reusable cell will already have viewWithTag 2 (since it was added when the cell being reused was created) so adding another view with tag 2 will create the issues like above. To overcome the above issue you should remove the earlier added viewWithTag 2 and than re-add the view with the same tag, like-
// remove (previously added) border if it exists
UIView *border = nil;
border = [cell.contentView viewWithTag:2];
if(border)
[border removeFromSuperview];
// again create border view
Update your cellForRowAtIndexPath: method as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// text view
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width-20, 50)];
view1.backgroundColor = [UIColor clearColor];
view1.tag = 0;
UILabel *title = [[UILabel alloc] initWithFrame:view1.frame];
title.text = #"Lorem ipsum";
title.textColor = [UIColor grayColor];
[view1 addSubview:title];
// options view
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
view2.backgroundColor = [UIColor orangeColor];
view2.tag = 1;
// border bottom
CGRect frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
if ([self.selectedIndexPath isEqual:indexPath]) {
frame.origin.y = 79; //expand
} else {
}
UIView *border = nil;
border = [cell.contentView viewWithTag:2];
if(border)
[border removeFromSuperview];
border = [[UIView alloc] initWithFrame:frame];
border.backgroundColor = [UIColor blueColor];
border.tag = 2;
cell.clipsToBounds = YES;
[cell.contentView addSubview:view1];
[cell.contentView addSubview:view2];
[cell.contentView addSubview:border];
// release your allocated instances after adding them
[view1 release];
[view2 release];
[border release];
return cell;
}
Also you should release your subviews which you have allocated like view1, view2, border after adding them to the cell's content view as
[view1 release];
[view2 release];
[border release];
This will make there retain count from 2 to 1 and when the cell is deallocated than they will be removed from there parent which is cell.
Table views re-use cells. When a cell is scrolled offscreen it is added to a queue, and will be re-used for the next cell to be scrolled onscreen. That means your configuration code in tableView:cellForRowAtIndexPath: method will be run again on the same cell multiple times at different indexPaths. Since you're just adding your border view every time your configuration code runs, they will stack one on top of the other. When you call viewWithTag: you will only get one of the multiple views you've added.
The correct approach is to create a custom cell (subclass of UITableViewCell) with properties for each subview that needs to be configured (IBOutlets if using xibs/storyboard), so that they can be accessed.
I have a custom cell in a UITableView. I programatically created a label with a height of 200 and a width of 50. When I do an NSLog in the customCell.m of the label's width and height, it gives me w: 50 and h: 200. But when I do an NSLog in mainViewController.m it gives me 0 for the height and width.
Not sure why it does that. I need to get the real height of the label in the mainViewController.m
Here's my code:
customCell.m
- (void)awakeFromNib {
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 200)];
[self.label setBackgroundColor:[UIColor yellowColor]];
[self.label setText:#"Hello"];
[self.myView addSubview:self.label];
CGRect myFrame = self.myView.frame;
myFrame.size.height = self.label.frame.size.height;
self.myView.frame = myFrame;
NSLog(#"%f", self.label.frame.size.height); // Results: 200.0000
}
mainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
customCell *cellVC = [[cutsomCell alloc] init];
NSLog(#"%f, %f", cellVC.label.frame.size.height, cellVC.frame.size.height); // Results: 0.0000, 44.0000
}
I setmyViewto 0 in the storyBoard.
If you don't understand something, please ask and I will be happy to explain.
Update
Here is my code:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 200)];
[self.label setBackgroundColor:[UIColor yellowColor]];
[self.label setText:#"Hello"];
[self.myView addSubview:self.label];
view
}
return self;
}
viewDidLoad
[self.tableView registerClass:[CustomCell class] forCellReuseIdentifier:#"cellID"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *customCell = #"customCell";
customCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellID" forIndexPath:indexPath];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:customCell owner:nil options:nil] objectAtIndex:0];
}
return cell;
}
The problem now is that when I run the app, no cells get shown. But I do get the correct NSLog.
In your mainViewController you just programmatically created the cellVC using alloc and then init, you did not create it from the nib, like you did it in the customCell.m so the awakeFromNib method was not called on it.
Update
Change back to using the custom cell from xib (instead of registerCell)
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCellxib"
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"CustomCellReuseID"]; // in the viewDidLoad of the mainViewController
Then deque the cell - you do not really need to check if the cell is nil because dequeue is now guaranteed to return a cell
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"customCellReuseID" forIndexPath:indexPath];
in your tableview datasource method
Keep the code currently in your awakeFromNib to initialize the custom cell added from nib. The default cell from the xib is fully initialized here so you should be able to customize the custom view. You do not need the initWithIdentifer anymore
You can optionally implement the table view delegate methods like:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// calculate the row height or return a constant
return 200.0;
}
The problem is that -awakeFromNib does not get called directly after -init
Try this:
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 200)];
[self.label setBackgroundColor:[UIColor yellowColor]];
[self.label setText:#"Hello"];
[self.myView addSubview:self.label];
CGRect myFrame = self.myView.frame;
myFrame.size.height = self.label.frame.size.height;
self.myView.frame = myFrame;
NSLog(#"%f", self.label.frame.size.height); // Results: 200.0000
return self;
}
I have written a subclass of UITableViewCell to allow horizontal swipe to give some actions to users. Here is what I am doing:
Create a scrollView
Create a buttonView and add in scrollView.
Create a UIButton and add all cell controls as subview to it. Add in scroll view.
Add scrollView to cell contentView.
For #3 I am setting the highlighted image to give a feel of user tap like in normal cell.
The issue is when my table view is loaded on iOS 6 with 6 cells and user tap on any of the cell, cell gets highlighted properly and the details are shown properly for the tapped cell. But if user scrolls up and first cell is re-used and user tap on the top cell (which is second row), cell next to it gets highlighted. If user scrolls up and purge 2 cells and tap on the top cell, cell 2 cells down it gets highlighted. Although tapped cell shows the data of the correct cell.
Any clue?
- (id)initWithStyle:(UITableViewCellStyle)iStyle reuseIdentifier:(NSString *)iReuseIdentifier andMenuButtonDetails:(NSArray *)iMenuButtonDetails {
if ((self = [super initWithStyle:iStyle reuseIdentifier:iReuseIdentifier])) {
self.catchWidth = kMenuButtonWidth * [iMenuButtonDetails count];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(kScreenOrigin, kScreenOrigin, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds) + self.catchWidth, CGRectGetHeight(self.bounds));
self.scrollView.delegate = self;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.scrollEnabled = YES;
[self.contentView addSubview:self.scrollView];
self.scrollViewButtonView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) - self.catchWidth, kScreenOrigin, self.catchWidth, CGRectGetHeight(self.bounds))];
[self.scrollView addSubview:self.scrollViewButtonView];
if ([iMenuButtonDetails count]) {
// Adding menu buttons to the cell.
CGFloat anXOffset = kScreenOrigin;
for (NSDictionary *aMenuButton in iMenuButtonDetails) {
if ([aMenuButton containsObjectForKey:kTitleKey]) {
UIButton *aButton = [[UIButton alloc] initWithFrame:CGRectMake(anXOffset, kScreenOrigin, kMenuButtonWidth, kCellHeight64)];
[aButton addTarget:self action:#selector(buttonSelected:) forControlEvents:UIControlEventTouchUpInside];
if ([aMenuButton containsObjectForKey:kButtonTagKey])
aButton.tag = [[aMenuButton stringForKey:kButtonTagKey] intValue];
aButton.titleEdgeInsets = UIEdgeInsetsMake(kScreenOrigin, 2.0, kScreenOrigin, 2.0);
aButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
[aButton.titleLabel setTextAlignment:NSTextAlignmentCenter];
[aButton setTitle:[aMenuButton stringForKey:kTitleKey] forState:UIControlStateNormal];
[aButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
if ([aMenuButton objectForKey:kButtonColorKey]) {
aButton.backgroundColor = [aMenuButton objectForKey:kButtonColorKey];
}
[self.scrollViewButtonView addSubview:aButton];
anXOffset += kMenuButtonWidth;
}
}
}
self.scrollViewContentView = [UIButton buttonWithType:UIButtonTypeCustom];
self.scrollViewContentView.frame = CGRectMake(kScreenOrigin, kScreenOrigin, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
if (![Utilities isIOS7orAbove]) {
[self.scrollViewContentView addTarget:self action:#selector(cellHighlighted) forControlEvents:UIControlEventTouchDown];
[self.scrollViewContentView addTarget:self action:#selector(cellCancelHighlight) forControlEvents:UIControlEventTouchDragExit];
}
[self.scrollViewContentView addTarget:self action:#selector(selectCell:) forControlEvents:UIControlEventTouchUpInside];
self.scrollViewContentView.backgroundColor = [UIColor whiteColor];
UIImage *aBGHighlightedImage = nil;
if ([Utilities isIOS7orAbove]) {
aBGHighlightedImage = [UIImage imageNamed:kCellHighlightedImageIOS7];
} else {
aBGHighlightedImage = [UIImage imageNamed:kCellHighlightedImageIOS6];
}
[self.scrollViewContentView setBackgroundImage:[aBGHighlightedImage stretchableImageWithLeftCapWidth:11.0f topCapHeight:0] forState:UIControlStateHighlighted];
[self.scrollView addSubview:self.scrollViewContentView];
[self.scrollViewContentView addSubview:self.imageView];
[self.scrollViewContentView addSubview:self.textLabel];
[self.scrollViewContentView addSubview:self.detailTextLabel];
}
- (void)prepareForReuse {
[super prepareForReuse];
self.scrollViewContentView.enabled = YES;
[self.scrollView setContentOffset:CGPointZero animated:NO];
}
- (UITableViewCell *)tableView:(UITableView *)iTableView cellForRowAtIndexPath:(NSIndexPath *)iIndexPath {
MyTableViewCell *aCell = (MyTableViewCell *)[iTableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (!aCell) {
aCell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier" andMenuButtonDetails:aMenuButtons];
}
// Set data on cell now
return aCell
}
Let me know if there is something I'm missing here, but it seems like you're adding a ton of complexity to your class for no reason. Are you familiar with UICollectionView?
Here's an example implementation (which scrolls horizontally):
#interface asdf () <UICollectionViewDataSource, UICollectionViewDelegate>
#property (strong, nonatomic) UICollectionView *collectionView;
#end
#implementation asdf
- (id)init
{
self = [super init];
if (self)
{
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.collectionViewLayout];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.view addSubview:self.collectionView];
NSString *className = NSStringFromClass([UICollectionViewCell class]);
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:className];
}
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.collectionView.frame = self.view.bounds;
}
- (UICollectionViewLayout *)collectionViewLayout
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 0;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
return layout;
}
#pragma mark - UICollectionView
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 5;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *className = NSStringFromClass([UICollectionViewCell class]);
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:className forIndexPath:indexPath];
// This is for dequeuing
NSInteger tag = 12324;
UIView *view = [cell viewWithTag:tag];
if (view)
[view removeFromSuperview];
view = [[UIView alloc] initWithFrame:cell.bounds];
view.tag = tag;
// Add all of your subviews to the view property
[cell addSubview:view];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(collectionView.bounds.size.width, 50);
}
#end
I wrote this quickly as a sample, so it's not tailored specifically to what you're building, but this should give you a nice idea of how simple it is to implement a UICollectionView.
This answer may come across as random for what you're asking, but when possible, you should always try to use what Apple provides over what you would spend precious hours re-inventing the wheel w/ & likely experience random nuances like yours.
I am trying to use a UITableView to create a photo stream (Like in say Instagram). I have code that should be working, but the image is still not being displayed. If i just create a UIImageView that is not part of the table, the image displays, but when I try to add it to the table, it doesn't appear. The table is appearing, just without the image. Here is the code -
View controller where table is being created
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// NSInteger sections = self.objects.count;
// if (self.paginationEnabled && sections != 0)
// sections++;
// return sections;
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PhotoCell";
PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.thumbImage = [UIImage imageNamed:self.thumbImage];
if (cell==nil) {
cell = [[PhotoCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
return cell;
}
Cell ViewController -
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.thumbImage];
imageView.frame = CGRectMake( 0.0f, 0.0f, 320.0f, 320.0f);
imageView.backgroundColor = [UIColor blackColor];
imageView.contentMode = UIViewContentModeScaleAspectFit;
self.photoButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.photoButton.frame = CGRectMake( 0.0f, 0.0f, 320.0f, 320.0f);
self.photoButton.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.photoButton];
NSLog(#"Working");
[self.contentView bringSubviewToFront:self.imageView];
}
return self; }
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state }
#pragma mark - UIView
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake( 20.0f, 0.0f, 280.0f, 280.0f);
self.photoButton.frame = CGRectMake( 20.0f, 0.0f, 280.0f, 280.0f); }
#end
I am sending the image captured in one view to the other using this -
PhotoCell *photoCell = [[PhotoCell alloc] init];
photoCell.thumbImage = self.thumbImage;
The problem with your code is that you are trying to set the image to an object which is potentially nil.
Your code will not work even if dequeueReusableCellWithIdentifier: returns a valid cell instance because you are adding the image view in initWithStyle:reuseIdentifier: method which will not be called if the cell is not nil.
I suggest you do something like follows
ViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PhotoCell";
PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[PhotoCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
[cell setImage:[UIImage imageNamed:self.thumbImage];
return cell;
}
Cell Subclass
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Maintain reference to the image view you create.
self.imageView = [[UIImageView alloc] init];
self.imageView.frame = CGRectMake( 0.0f, 0.0f, 320.0f, 320.0f);
self.imageView.backgroundColor = [UIColor blackColor];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.photoButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.photoButton.frame = CGRectMake( 0.0f, 0.0f, 320.0f, 320.0f);
self.photoButton.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.photoButton];
NSLog(#"Working");
[self.contentView bringSubviewToFront:self.imageView];
}
return self; }
-(void)setImage:(UIImage *)image
{
[self.imageView setImage:image];
}
On the same note, I would suggest tht you create prototype cells in the xib/storyboard if you are using one. That would be much easier and elegant way to handle this case.
Other than what has been discussed above, you should use an asynchronous image loading for your table view cell or PhotoCell. This can be easily done with UIImageView+AFNetworking.
I see that you're looking to build an Instagram photo stream. Take a look at STXDynamicTableView which is a sample code for this. All you need to do is just hook-up the asynchronous image loading into it.
I have a subclass of UITableViewCell, and I am having problems with scrolling. All of the subviews are added to the cell in the storyboard, except for one UIView. I want to add this UIView as a subview of the cell based on a condition. The problem is that when the cells are scrolled off and onto the screen, the UIView is added to the cell a second time, or to the wrong cell. Here is my code, can you tell me what I am doing wrong?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
WavesFeedCell *cell = (WavesFeedCell *)[tableView dequeueReusableCellWithIdentifier:WavesFeedCellIdentifier forIndexPath:indexPath];
cell.cellWaveObject = [self.wavesArray objectAtIndex:indexPath.row];
//set the frames and text for the labels
cell.timeStampLabel.text = #"14m";
cell.waveTextLabel.text = cell.cellWaveObject.waveString;
cell.wavedByLabel.text = [NSString stringWithFormat:#"Waved by %#", cell.cellWaveObject.wavedByString];
//round the corners of the image view
[self setCornerRadiusForImageView:cell.profilePictureImageView];
//does the wave object have any agrees?
if (cell.cellWaveObject.numberOfAgrees > 0)
{
UIView *agreedView = [[UIView alloc] init];
UILabel *numberOfAgreesLabel = [[UILabel alloc] init];
numberOfAgreesLabel.font = [UIFont boldSystemFontOfSize:13.0f];
numberOfAgreesLabel.textColor = [UIColor whiteColor];
if (cell.cellWaveObject.numberOfAgrees > 1)
{
numberOfAgreesLabel.text = [NSString stringWithFormat:#"+%i Agree", cell.cellWaveObject.numberOfAgrees];
}
else
{
numberOfAgreesLabel.text = [NSString stringWithFormat:#"+%i Agrees", cell.cellWaveObject.numberOfAgrees];
}
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:AgreedViewImage]];
//get the width of the string
CGSize constraintSize = CGSizeMake(242.0f, 16.0f);
CGSize stringSize = [numberOfAgreesLabel.text sizeWithFont:numberOfAgreesLabel.font constrainedToSize:constraintSize];
CGFloat agreedViewWidth = stringSize.width + 10.0f;
//adjust the frame and add it to the cell
agreedView.frame = CGRectMake(310.0f - agreedViewWidth, cell.wavedByLabel.frame.origin.y, agreedViewWidth, 14.0f);
backgroundImageView.frame = CGRectMake(5.0f, 0.0f, agreedView.frame.size.width, agreedView.frame.size.height);
numberOfAgreesLabel.frame = CGRectMake(5.0f, 0.0f, agreedView.frame.size.width, agreedView.frame.size.height);
[agreedView addSubview:backgroundImageView];
[agreedView addSubview:numberOfAgreesLabel];
[cell.contentView addSubview:agreedView];
return cell;
}
else
{
return cell;
}
}
May be added subview is not removing from cell.Content View .
Try using following code within cellForRow method
UIView *agreedView=(UIView*)[cell.contentView viewWithTag:21];
//does the wave object have any agrees?
if (cell.cellWaveObject.numberOfAgrees > 0)
{
if (!agreedView) {
agreedView=[[UIView alloc] init];
agreedView.tag=21;
UILabel *numberOfAgreesLabel = [[UILabel alloc] init];
numberOfAgreesLabel.font = [UIFont boldSystemFontOfSize:13.0f];
numberOfAgreesLabel.textColor = [UIColor whiteColor];
numberOfAgreesLabel.tag=22;
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:AgreedViewImage]];
backgroundImageView.tag=23;
[agreedView addSubview:backgroundImageView];
[agreedView addSubview:numberOfAgreesLabel];
[cell.contentView addSubview:agreedView];
}
numberOfAgreesLabel=(UILabel*)[agreedView viewWithTag:22];
backgroundImageView=(UIImageView*)[agreedView viewWithTag:23];
if (cell.cellWaveObject.numberOfAgrees > 1)
{
numberOfAgreesLabel.text = [NSString stringWithFormat:#"+%i Agree", cell.cellWaveObject.numberOfAgrees];
}
else
{
numberOfAgreesLabel.text = [NSString stringWithFormat:#"+%i Agrees", cell.cellWaveObject.numberOfAgrees];
}
//get the width of the string
CGSize constraintSize = CGSizeMake(242.0f, 16.0f);
CGSize stringSize = [numberOfAgreesLabel.text sizeWithFont:numberOfAgreesLabel.font constrainedToSize:constraintSize];
CGFloat agreedViewWidth = stringSize.width + 10.0f;
//adjust the frame and add it to the cell
agreedView.frame = CGRectMake(310.0f - agreedViewWidth, cell.wavedByLabel.frame.origin.y, agreedViewWidth, 14.0f);
backgroundImageView.frame = CGRectMake(5.0f, 0.0f, agreedView.frame.size.width, agreedView.frame.size.height);
numberOfAgreesLabel.frame = CGRectMake(5.0f, 0.0f, agreedView.frame.size.width, agreedView.frame.size.height);
return cell;
}
else
{
if (agreedView) {
[agreedView removeFromSuperview];
}
return cell;
}
Better you set frames for your custom views in subclassed UITableView cell's class
hear is the sample code
//.h file of subclassed UITableView cell
#import <UIKit/UIKit.h>
#interface WavesFeedCell : UITableViewCell
#property(nonatomic, retain)UILabel *timeStampLabel;
#property(nonatomic, retain)UILabel *waveTextLabel;
#property(nonatomic, retain)UILabel *wavedByLabel;
#property(nonatomic, retain) id cellWaveObject; //your object from array
#end
//.m file subclassed UITableView cell
#import "WavesFeedCell.h"
#implementation WavesFeedCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectZero];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectZero];
UILabel *label3 = [[UILabel alloc]initWithFrame:CGRectZero];
self.timeStampLabel = label1;
self.waveTextLabel = label2;
self.wavedByLabel = label3;
//these are added with zero rect
[self addSubview:label1];
[self addSubview:label2];
[self addSubview:label3];
//for agreed imageview
UIImageView *agreedImgView = [[UIImageView alloc]initWithFrame:CGRectZero];
agreedImgView.tag = 200; //to access in layoutsubviews.
[self addSubview:agreedImgView];
//without ARC
[agreedImgView release];
[label1 release];
[label2 release];
[label3 release];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)layoutSubviews
{
[super layoutSubviews];
//hear set frames for all labels
self.timeStampLabel.frame = CGRectMake(5, 5, self.bounds.size.width-30.0f, 40.0f);
self.waveTextLabel.frame = CGRectMake(5, 45, self.bounds.size.width-30.0f, 40.0f);
self.wavedByLabel.frame = CGRectMake(5, 95, self.bounds.size.width-30.0f, 40.0f);
//hear you check weather it is agreed or not
if(self.cellWaveObject.numberOfAgrees > 1)
{
UIImageView *agreedView = (UIImageView *)[self viewWithTag:200];
//set frme for imageview as you did
// remember dont add any views hear and set your required frames only because this method called many times
}
//in other class
//.m file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
WavesFeedCell *cell = [self.aTableView dequeueReusableCellWithIdentifier:#"WavesFeedCell"];
if(cell == nil)
{
cell = [[WavesFeedCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"WavesFeedCell"];
}
//set cell properties
return cell;
}