how to change width UITableViewCell and use in UITableView - ios

I have one class ViewController that I to create TableView in it with code not nib file and I want custom cell with UITableViewCell that has nib file.
I create TableView with code that has 320px width and I want create custom cell with UITableViewCell that my cells had 300px width and put in my TableView.
notice: I want these cells put center my table and these cells have 10px distance from two side!!!
this is my code:
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
table = [self makeTableView];
[self.view addSubview:table];
[self.view setBackgroundColor: RGB(193,60,46)]; //will give a UIColor objct
name = [[NSArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
// Do any additional setup after loading the view from its nib.
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
-(UITableView *)makeTableView
{
CGFloat x = 0;
CGFloat y = 0;
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;
CGRect tableFrame = CGRectMake(x, y, width, height);
UITableView *tableView = [[UITableView alloc]initWithFrame:tableFrame style:UITableViewStyleGrouped];
tableView.rowHeight = 60;
tableView.sectionFooterHeight = 22;
tableView.sectionHeaderHeight = 22;
tableView.scrollEnabled = YES;
tableView.showsVerticalScrollIndicator = YES;
tableView.userInteractionEnabled = YES;
tableView.bounces = YES;
tableView.backgroundColor = [UIColor clearColor];
tableView.delegate = self;
tableView.dataSource = self;
return tableView;
}
#pragma mark Table View Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = (CustomCell *)[self.table dequeueReusableCellWithIdentifier:#"myCell"];
if (cell == nil)
{
NSArray *topLevelObject = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for (id currentObject in topLevelObject) {
if ([currentObject isKindOfClass:[CustomCell class]]) {
cell = (CustomCell *)currentObject;
break;
}
}
}
// Configure the cell...
cell.titleLable.text = [name objectAtIndex:indexPath.row];
return cell;
}
this is my code : TableCode

I have a UITableView with a width of 685.
I created Custom UITableViewCell with a width of 685 also.
I have added two labels.
I aligned a label in such a way, the spacing for left and right are the same.

afaik, cells are always the width of the table and you cant change that, you can fake it by making the content view of the cell transparent, then place another view with all your content in it that is a smaller width than the table

Related

UITableView subview inside UITableViewCell won't display

I'm trying to create a UITableview, where each cell contains another UITableView. It's basically a list of 2-3 rows, where each row then has a sublist of 2-3 rows inside.
The main ViewController behaves just like any other TableViewController, and inside the cellForRowAtIndexPath, it attempts to add a SubTableViewController.view with a dynamic height. The SubTableViewController is the second tableview and each has their own Datasource.
The problem I'm running into is the SubTableViewController appears to render properly using the debugger, with the correct data and number of cells, but it simply isn't appearing when rendering. I noticed it has a contentSize height of "0" in its ViewDidAppear, despite having 2+ rows produced with height. The project uses AutoLayout but the SubTableViewController's frame is set programmatically when added.
Any ideas what I can do to get something to appear here?
Structure of Data (periods are the subTable)
[{name:"activity 1",
periods:[{name:"period1",desc:"desc1"},
{name:"period2",desc:"desc2"},
{name:"period3",desc:"desc3"}
]
},
{name:"activity 2",
periods:[{name:"period1",desc:"desc1"},
{name:"period2",desc:"desc2"},
{name:"period3",desc:"desc3"}
]
}]
ViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_data count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
UIImageView *imageView = (UIImageView*)[cell viewWithTag:1];
UIView *subTableView = (UIView*)[cell viewWithTag:3];
return imageView.frame.size.height + subTableView.frame.size.height + 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"tableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
ActivityModel *model = _data[indexPath.row];
UILabel *nameLabel = (UILabel*)[cell viewWithTag:2];
nameLabel.text = model.name;
UIView *internalView = (UIView*)[cell viewWithTag:10];
SubTableViewController *subTableViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SubTableViewController"];
subTableViewController.activityModel = model;
subTableViewController.view.tag = 3;
subTableViewController.view.frame = CGRectMake(0,
60,
internalView.frame.size.width,
subTableViewController.view.frame.size.height);
[internalView addSubview:subTableViewController.view];
[internalView bringSubviewToFront:subTableViewController.view];
[subTableViewController.tableView reloadData];
return cell;
}
SubTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
int height = 0;
for (int section = 0; section < [self numberOfSectionsInTableView:_tableView]; section++){
for(int row = 0; row < [self tableView:_tableView numberOfRowsInSection:section]; row++){
height += [self tableView:_tableView heightForRowAtIndexPath:[NSIndexPath indexPathForItem:row inSection:section]];
}
}
CGRect tableFrame = self.tableView.frame;
tableFrame.size.height = height;
self.tableView.frame = tableFrame;
CGRect viewFrame = self.view.frame;
viewFrame.size.height = height;
self.view.frame = viewFrame;
[self.view bringSubviewToFront:_tableView];
// [self.tableView layoutIfNeeded];
// [self.tableView setNeedsDisplay];
// [self.tableView reloadData];
// _tableView.contentSize = CGSizeMake(600, 52);
self.view.backgroundColor = [UIColor redColor];
self.tableView.backgroundColor = [UIColor blueColor];
self.tableView.hidden = NO;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_activityModel.periods count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
UILabel *nameLabel = (UILabel*)[cell viewWithTag:3];
UITextView *textView = (UITextView*)[cell viewWithTag:5];
float textViewHeight = [textView.text sizeWithFont:[UIFont systemFontOfSize:13] constrainedToSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 40, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping].height;
return nameLabel.frame.size.height + textViewHeight + 20;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"tableViewCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
PeriodModel *model = _activityModel.periods[indexPath.row];
UILabel *nameLabel = (UILabel*)[cell viewWithTag:3];
UILabel *durationLabel = (UILabel*)[cell viewWithTag:4];
UITextView *textView = (UITextView*)[cell viewWithTag:5];
nameLabel.text = model.name;
durationLabel.text = [NSString stringWithFormat:#"%d minutes", (int)(model.durationSeconds/60)];
textView.text = model.description;
textView.textContainerInset = UIEdgeInsetsZero;
textView.textContainer.lineFragmentPadding = 0;
textView.scrollEnabled = NO;
CGRect frame = textView.frame;
frame.size.height = [textView.text sizeWithFont:[UIFont systemFontOfSize:12] constrainedToSize:CGSizeMake(cell.contentView.frame.size.width, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping].height;
textView.frame = frame;
return cell;
}
Simulator Image. The title is the outer UITableCell, and below it in red is the added SubTableViewController.view. The UITableView should cover the red, but is not appearing at all here. It is not hidden, underneath, etc.
Do not put a table view inside your cells.
There is little benefit to doing this for your described use. Use sections and rows. Each section would be your current cell. And each row in that section would be a row from your current embedded table view.
Further, if your internal table views had differing sizes you would be needing to calculate all of the internal cell heights for each external cell. That is exactly what happens with sections and rows, but you as the developer only need to worry about the rows and UITableView will handle the section sizing.

UITableView methods get overriden by TableView size

The code in questions is below:
-(void)addSpeedTable {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"newCell"];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.tableView.rowHeight = 45;
self.tableView.sectionFooterHeight = 22;
self.tableView.sectionHeaderHeight = 22;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView = _tableView;
NSLog(#"TableView Frame %#", NSStringFromCGRect(self.tableView.frame));
[self.view addSubview:self.tableView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"newCell"];
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.textLabel.text = #"Test";
return cell;
}
As you can see if I have a section set to 1 and row set to 1, yet when the view is added the table takes up the entire screen, which I assume is because I initiate with a frame of the view bounds.
Is there any way to force the table to only be the size of the rows required?
My plan is to add more than one table to this single view and I want them appearing one after the other along with title labels and a scrollview. I want the height to be decided by the number of rows.
Thanks
UPDATED CODE THANKS TO THE CORRECT ANSWER:
-(void)addSpeedTable {
CGRect frame = self.tableView.frame;
frame.size.height = (40 * resultHeadings.count)+35;
frame.size.width = self.view.frame.size.width;
//If more than one table has been shown increase Y axis height for view
if(tablesDisplayed > 0) {
NSLog(#"Tables displayed greater than zero");
viewHeight = viewHeight + frame.size.height;
}
frame.origin.y = viewHeight;
frame.origin.x = 0;
self.tableView = [[UITableView alloc] initWithFrame:frame];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"newCell"];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.tableView.rowHeight = 40;
self.tableView.sectionFooterHeight = 0;
self.tableView.sectionHeaderHeight = 22;
self.tableView.scrollEnabled = NO; // Disable ScrollView
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView = _tableView;
NSLog(#"TableView Frame %#", NSStringFromCGRect(frame));
[self.view addSubview:self.tableView];
tablesDisplayed++;
}
As I'm adding more than one table in the long run I calculate the height based on a calculation. This works great.
Here are two things you could try. Without knowing where addSpeedTable is called from, I'd err on putting this in your cellForRowAtIndexPath method.
Set the height to the self.tableView.contentHeight
CGRect frame = self.tableView.frame;
frame.size.height = self.tableView.contentSize.height;
self.tableView.frame = frame;
Call [self.tableView sizeToFit]

scrollViewDidScroll method not giving reference to all scrollviews from table view

I have created tableView with custom cells that contain image view and scrollView. All scroll views contain labels wider than screen bounds, so when I scroll to left/right I want all scrollViews to scroll in same direction. Problem is I don't know how to get reference to each scrollView in scrollViewDidScroll method.
my viewController class:
#import "EPGViewController.h"
#interface EPGViewController (){
NSArray *EPGList;
int scrollPositionX;
}
#end
#implementation EPGViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBarHidden = false;
EPGList = [NSMutableArray arrayWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10",#"11",#"12", nil];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return EPGList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *hlCellID = #"EPGCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:hlCellID];
if(cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:hlCellID];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
UILabel *label = (UILabel *)[cell viewWithTag:15];
label.text = EPGList[indexPath.row];
UIScrollView *scrolView = (UIScrollView *)[cell viewWithTag:16];
scrolView.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];
scrolView.delegate = self;
scrolView.tag = indexPath.row+101;
scrolView.scrollEnabled = YES;
scrolView.contentSize = CGSizeMake(scrolView.frame.size.width,scrolView.frame.size.height);
[scrolView setShowsHorizontalScrollIndicator:NO];
[scrolView setShowsVerticalScrollIndicator:NO];
int i=0;
for(i=0;i<15;i++){
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0+i*100, 0, 100, 100)];
label.text = #"HELLO";
label.textColor = [UIColor blackColor];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont fontWithName:#"ArialMT" size:18];
[scrolView addSubview:label];
scrolView.contentSize = CGSizeMake(scrolView.frame.size.width+i*label.frame.size.width,scrolView.frame.size.height);
}
[cell addSubview:scrolView];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 80.0;
}
- (void)scrollViewDidScroll:(UIScrollView *)callerScrollView {
scrollPositionX = callerScrollView.contentOffset.x;
//if this is called with table view exit
if (callerScrollView == self.tableView) return;
int indexPath = callerScrollView.tag-101;
NSLog(#"TAG: %d",indexPath);
for (UITableViewCell *cell in self.tableView.visibleCells) {
//TODO: Don’t use tags.
UIScrollView *cellScrollView = (UIScrollView *)[cell viewWithTag:16];
if (callerScrollView == cellScrollView) continue;
cellScrollView.contentOffset = CGPointMake(scrollPositionX, 0);
}
}
#end
EDIT:
I managed to solve my problem by deleting line where I add different tags to scrollviews in table view. now I just set offset to scrollview with tag 16.
There are multiple wrong things in your code. Here is better implementation:
- (void)scrollViewDidScroll:(UIScrollView *)callerScrollView {
scrollPositionX = callerScrollView.contentOffset.x;
if (callerScrollView == self.tableView) return;
for (UITableViewCell *cell in self.tableView.visibleCells) {
//TODO: Don’t use tags.
UIScrollView *cellScrollView = (UIScrollView *)[cell viewWithTag:16];
if (callerScrollView == cellScrollView) continue;
cellScrollView.contentOffset = CGPointMake(scrollPositionX, 0);
}
}
Some additonal notes:
This method will be called by table view too, so you will have to check that.
Don’t use any indexes, just plain iteration.
I used checking of scrollViews, but basically there it would be OK without it.
Using tags to identify subviews is not a good idea.
Don’t call reloadData every time!
You should use [tableView visibleCells]; in order to get all cells that are visible at this moment.
You could use UITableView's visibleCells method to get all visible cells and get your scrollviews from there (you can use viewwithTag like you do, but on all cells).
Then you would have to remember to adjust the scrollview position as cells are reused/recreated - probably keep the scrolled offset as a property of your View Controller.
The problem is that you're using dequeueReusableCellWithIdentifier rather than just looping through the cells that have already been displayed.
Do something like:
for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
{
if (!(indexPath.section == j && indexPath.row == i))
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
UIScrollView *scrollView = (UIScrollView *)[cell viewWithTag:16];
scrollView.contentOffset = CGPointMake(position_x, scrollView.frame.size.height);
}
}
}

Dynamically resizing UITableViewCell based on text input

I am trying to dynamically resize some UITableViewCell's based on the height of UITextView's contained within them.
There's loads of solutions to this by keeping a pointer to the UITextView and getting it's content size in heightForRowAtIndexPath however when the whole table is created dynamically with an unknown number of rows and an unknown number of them rows contain UITextView's this just isn't possible.
It would be easy if I could call the cell in question during heightForRowAtIndexPath but that causes an infinite loop and crash as this method is called before any cell's are even created.
Any other solutions?
I am using a UITableViewCell subclass for my cell like this:
- (void)initalizeInputView {
// Initialization code
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.textView = [[UITextView alloc] initWithFrame:CGRectZero];
self.textView.autocorrectionType = UITextAutocorrectionTypeDefault;
self.textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.textView.textAlignment = NSTextAlignmentRight;
self.textView.textColor = [UIColor lightBlueColor];
self.textView.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17];
self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textView.keyboardType = UIKeyboardTypeDefault;
[self addSubview:self.textView];
self.textView.delegate = self;
}
- (BOOL)resignFirstResponder {
if (_delegate && [_delegate respondsToSelector:#selector(tableViewCell:didEndEditingWithLongString:)]) {
[_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
}
return [super resignFirstResponder];
}
- (void)setKeyboardType:(UIKeyboardType)keyboardType
{
self.textView.keyboardType = keyboardType;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self initalizeInputView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self initalizeInputView];
}
return self;
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
[self.textView becomeFirstResponder];
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
[self.textView becomeFirstResponder];
}
}
- (void)setStringValue:(NSString *)value {
self.textView.text = value;
}
- (NSString *)stringValue {
return self.textView.text;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
// For keyboard scroll
UITableView *tableView = (UITableView *)self.superview;
AppSetupViewController *parent = (AppSetupViewController *)_delegate;
parent.activeCellIndexPath = [tableView indexPathForCell:self];
}
- (void)textViewDidChange:(UITextView *)textView
{
if (textView.contentSize.height > contentRowHeight) {
contentRowHeight = textView.contentSize.height;
UITableView *tableView = (UITableView *)self.superview;
[tableView beginUpdates];
[tableView endUpdates];
[textView setFrame:CGRectMake(0, 0, 300.0, textView.contentSize.height)];
}
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
if (_delegate && [_delegate respondsToSelector:#selector(tableViewCell:didEndEditingWithLongString:)]) {
[_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
}
UITableView *tableView = (UITableView *)self.superview;
[tableView deselectRowAtIndexPath:[tableView indexPathForCell:self] animated:YES];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect editFrame = CGRectInset(self.contentView.frame, 10, 10);
if (self.textLabel.text && [self.textLabel.text length] != 0) {
CGSize textSize = [self.textLabel sizeThatFits:CGSizeZero];
editFrame.origin.x += textSize.width + 10;
editFrame.size.width -= textSize.width + 10;
self.textView.textAlignment = NSTextAlignmentRight;
} else {
self.textView.textAlignment = NSTextAlignmentLeft;
}
self.textView.frame = editFrame;
}
Which is created in cellForRowAtIndexPath like this:
else if ([paramType isEqualToString:#"longString"]) {
MyIdentifier = #"AppActionLongString";
LongStringInputTableViewCell *cell = (LongStringInputTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
cell.textLabel.text = [[[_selectedAction objectForKey:#"parameters"] objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.params = [[_selectedAction objectForKey:#"parameters"] objectAtIndex:indexPath.row];
cell.textView.text = [results objectAtIndex:indexPath.row];
return cell;
}
Simply passing back the height to a variable in my ViewController is no good because like I said, there could be several of these cells within the table.
Thanks
Use this method to dynamically resize your tableviewCell. First store the user input in NSMutable Array and after that reload table. Hope it will help you.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *msg =[self.messages objectAtIndex:indexPath.row];
CGSize textSize = { 120, 10000.0 };
CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:15]
constrainedToSize:textSize
lineBreakMode:UILineBreakModeWordWrap];
return size.height+20;
}
I needed a dynamic table view cell height based on the amount of text to be displayed in that cell. I solved it in this way:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!isLoading)
{
if ([self.conditionsDataArray count]>0)
{
Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];
int height;
UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)]; //you can set your frame according to your need
textview.text = condition.comment;
textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[tableView addSubview:textview];
textview.hidden = YES;
height = textview.contentSize.height;
NSLog(#"TEXT VIEW HEIGHT %f", textview.contentSize.height);
[textview removeFromSuperview];
[textview release];
return height;
}
return 55; //Default height, if data is in loading state
}
Notice that the Text View has been added as Subview and then made hidden, so make sure you add it as SubView otherwise it's height will not be considered.
It would be easy if I could call the cell in question during heightForRowAtIndexPath but that causes an infinite loop and crash as this method is called before any cell's are even created. Any other solutions?
You can. I would guess you're attempting to call cellForRowAtIndexPath, which will cause an infinite loop. But you should rather be dequeuing the cell directly by calling dequeueReusableCellWithIdentifier.
See the table view delegate implementation of TLIndexPathTools. The heightForRowAtIndexPath method looks like this:
(EDIT Initially forgot to include the method prototypeForCellIdentifier that actually dequeues the cell.)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id item = [self.dataModel itemAtIndexPath:indexPath];
NSString *cellId = [self cellIdentifierAtIndexPath:indexPath];
if (cellId) {
UITableViewCell *cell = [self prototypeForCellIdentifier:cellId];
if ([cell conformsToProtocol:#protocol(TLDynamicSizeView)]) {
id<TLDynamicSizeView> v = (id<TLDynamicSizeView>)cell;
id data;
if ([item isKindOfClass:[TLIndexPathItem class]]) {
TLIndexPathItem *i = (TLIndexPathItem *)item;
data = i.data;
} else {
data = item;
}
CGSize computedSize = [v sizeWithData:data];
return computedSize.height;
} else {
return cell.bounds.size.height;
}
}
return 44.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView prototypeForCellIdentifier:(NSString *)cellIdentifier
{
UITableViewCell *cell;
if (cellIdentifier) {
cell = [self.prototypeCells objectForKey:cellIdentifier];
if (!cell) {
if (!self.prototypeCells) {
self.prototypeCells = [[NSMutableDictionary alloc] init];
}
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//TODO this will fail if multiple tables are being used and they have
//overlapping identifiers. The key needs to be unique to the table
[self.prototypeCells setObject:cell forKey:cellIdentifier];
}
}
return cell;
}
This uses a protocol TLDynamicSizeView that any cell can implement to have it's height calculated automatically. Here is a working example project. The cell's implementation of the protocol looks like this:
#implementation DynamicHeightCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.originalSize = self.bounds.size;
self.originalLabelSize = self.label.bounds.size;
}
- (void)configureWithText:(NSString *)text
{
self.label.text = text;
[self.label sizeToFit];
}
#pragma mark - TLDynamicSizeView
- (CGSize)sizeWithData:(id)data
{
[self configureWithText:data];
//the dynamic size is calculated by taking the original size and incrementing
//by the change in the label's size after configuring
CGSize labelSize = self.label.bounds.size;
CGSize size = self.originalSize;
size.width += labelSize.width - self.originalLabelSize.width;
size.height += labelSize.height - self.originalLabelSize.height;
return size;
}
#end
just comment
if (cell == nil)
Hope, this will help you.

UISwitch not shown in UITable

I have made a UITable with some data and I had include a UISwitch in, but it not shown in the table when its run.
in .h
#interface CalcViewController : UITableViewController {
IBOutlet UITableView *mainTableView;
NSMutableArray *courseMURArray;
NSMutableArray *switchStates;
}
and in .m
- (void)viewDidLoad
{
[super viewDidLoad];
switchStates = [[NSMutableArray alloc] init ];
int i = 0;
for (i = 0; i < 33; i++) {
[switchStates addObject:#"OFF"];
}
}
and in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
UISwitch *theSwitch = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
theSwitch = [[UISwitch alloc]initWithFrame:CGRectZero];
theSwitch.tag = 100;
CGRect frame = theSwitch.frame;
frame.origin.x = 230;
frame.origin.y = 8;
theSwitch.frame = frame;
[theSwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:theSwitch];
}else{
theSwitch = [cell.contentView viewWithTag:100];
}
if ([[switchStates objectAtIndex:indexPath.row] isEqualToString:#"ON"]) {
theSwitch.on = YES;
}else{
theSwitch.on = NO;
}
return cell;
}
and this is selector method
-(void) switchChanged: (UISwitch *) sender{
UITableViewCell *theParentCell = [[ sender superview] superview];
NSIndexPath * indexPathOfSwitch = [mainTableView indexPathForCell:theParentCell];
if (sender.on) {
[switchStates replaceObjectAtIndex:indexPathOfSwitch.row withObject:#"ON"];
}else{
[switchStates replaceObjectAtIndex:indexPathOfSwitch.row withObject:#"OFF"];
}
}
every thing is ok with the data but its not with are there any problem?
When you set up the cell in cell for RowAtIndexPath, you're setting the frame to CGRectZero, a rect at position (0,0) with width = height = 0. You then reset the position, but you never reset the the width & height.
After your 2 frame.origin lines add:
frame.size.width = XX;
frame.size.height = YY;
or just use CGRectMake(X, Y, width, height) to make the frame.
In your cellForRowAtIndexPath, if the cell is nil, then you initialise the UISwitch and add it to the cell. What if the cell is not nil initially?
Let's say, UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"] returns a valid cell, then no switch will be created at all.
You may want to verify whether you have specified "Cell" as the identifier for the UITableViewCell in interface builder just in case.
Alternatively, move the code for initialising the UISwitch outside of the "if(cell==nil)". See if this solves your issue. The "if(cell==nil)" block is supposedly for initialising cell if dedequeueReusableCellWithIdentifier: returns nil.
Also, you are using a tag number of 100 for all switches and in the else block, you initialise theSwitch with contentView of tag 100. Which UISwitch should iOS assign to theSwitch if you have more than one switch? You might want to refer to my post on how to set tag numbers correctly.

Resources