I have a TableView with a dark transparent
background which I'd like to have a padding
I tried to accomplish that using contentInsets,
contentSize and contentOffset:
CGFloat padding = 10.0f;
CGSize size = self.tableView.bounds.size;
size.width -= (padding*2);
size.height -= (padding*2);
self.tableView.contentSize = size;
self.tableView.contentInset = UIEdgeInsetsMake(padding, padding, padding, padding);
self.tableView.contentOffset = CGPointMake(-padding, -padding);
That doesn't work.
I get the padding, but neither are the cells
resized nor respositioned.
I know, I could nest the TableView inside another View,
but there should be another solution.
EDIT:
I actually had a misconception as to the meaning of 'contentSize'.
It's not the viewport's size but the actual size of, you name it, the content.
So I probably will have to..
resize the individual cells if possible (might collide with the TableView's layout process)
apply a content offset to the TableView as above
For width, you are going to have to mess with each cells frame. as for top and bottom inset, use setContentInset:
If you want a paffing for your tableview simply change its frame.
If you want a padding for your cells, try this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Custom";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
CGRect cellFrame = CGRectMake(20,0,200,200); //CHANGE FRAME FOR YOUR APP
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:cellFrame reuseIdentifier:CellIdentifier] autorelease];
}
//INSERT YOUR CODE TO RETRIVE TEXT TO INSERT INTO A CELL
return cell;
}
Related
I have a uitableview with uitableviewcells however some of my text is so long its going right to the edge of the cell, where my accessory tick view is going to be when selected..
I am currently wrapping the text if it extends beyond the width and it goes onto the second line.. However I was hoping there is a nice way to restrict the width of this UITableViewCell label.
Inside your cellForRowAtIndexPath: function. The first time you create your cell:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:17.0];
}
Now specify how large your UITableViewCell will be, so do that in your heightForRowAtIndexPath function:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *str = [[arrTexts objectAtIndex:indexPath.row]; // filling text in label
CGSize maximumSize = CGSizeMake(300, 100); // change width and height to your requirement
CGSize strSize = [str sizeWithFont:[UIFont fontWithName:#"Helvetica" size:17] constrainedToSize:maximumSize lineBreakMode:UILineBreakModeWordWrap] //dynamic height of string depending on given width to fit
return (10+strSize.height+10) // caculate on your bases as u have string height
}
In cellForRowAtIndexPath Set the width of the textLabel
cell.textLabel.frame = CGRectMake(cell.textLabel.frame.origin.x, cell.textLabel.frame.origin.y, 280, cell.textLabel.frame.size.height);
thats all.
I think you need subclass UITableViewCell to override -layoutSubviews... call super, then frame your label appropriately. Constraints my be of some help, but I haven't used them on iOS yet. (Assuming the problem is the built-in layout function make the label as wide as it needs to be to accommodate your text)
There are two ways to do so.
1) Create a custom UITableViewCell class, add your UILabels with whatever position & size you want. And then use it in cellForRowAtIndexPath method.
2) Else, don’t use default UILabels of UITableViewCell ie. textLabel & detailTextLabel, add your own UILabels in cell with whatever position & size you want.
guys.
I have UITableView with different cells and I have code, which counts height. In one project it works perfect, but in second it returns height equals 0.
What could be causing this?
My code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CGFloat cellWidth = 320.0f;
CGSize size = [cell.textLabel.text sizeWithFont:cell.textLabel.font constrainedToSize:CGSizeMake(cellWidth, CGFLOAT_MAX) lineBreakMode:cell.textLabel.lineBreakMode];
CGFloat height = size.height;
NSLog(#"Height: %f", height);
return height;
}
The heightForRowAtIndexPath: delegate method gets called before the cellForRowAtIndexPath: delegate method. In your code you are calculating your cell height based on cell.textLabel.text, but the text in the cell has not been set yet.
You need to get the text to use in this method from somewhere else other than the table cell (presumably you can get it from wherever you are getting it from when you set the textlabel.text value in cellForRowAtIndexPath).
I'm making a horizontal table view like the Pulse news reader. I've found several examples online and have it working, but am wondering when we need to set the view.frame property after a transformation.
The examples I've found reset the frame of the horizontal table view within the vertical table view cell after the 90 degree rotation
self.tableViewCell.horizontalTableView.transform = rotateTable;
self.tableViewCell.horizontalTableView.frame = CGRectMake(0, 0, self.tableViewCell.horizontalTableView.frame.size.width, self.tableViewCell.horizontalTableView.frame.size.height);
More Context:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
TableViewCell *cell = (TableViewCell*)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
self.tableViewCell.horizontalTableView.transform = rotateTable;
self.tableViewCell.horizontalTableView.frame = CGRectMake(0, 0, self.tableViewCell.horizontalTableView.frame.size.width, self.tableViewCell.horizontalTableView.frame.size.height);
self.tableViewCell.contentArray = [self.arrays objectAtIndex:indexPath.section];
self.tableViewCell.horizontalTableView.allowsSelection = YES;
cell = self.tableViewCell;
self.tableViewCell = nil;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
But don't reset the frame of the horizontal table cell after the cell's transformation (rotation):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.horizontalTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"GameTableViewCell" owner:self options:nil];
cell = self.gameTableCell;
self.gameTableCell = nil;
}
CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;
return cell;
}
I tried resetting the cell's frame and it had no effect on the output, even if I supplied
cell.frame = CGMakeRect(200, 200, cell.frame.size.height, cell.frame.size.width)
Which should have moved the cell around the Table View, no?
If I don't reset the frame of self.tableViewCell.horizontalTableView.frame the horizontal table is rotated, but in the wrong location.
Why is it that I need to reset the frame of the horizontal Table View after rotating it, but not the individual cells (which are also rotated)?
Thanks!
// illustration by iPortable
ahh ok after reading it again I understand what you're asking ^^
Setting the frame results in redrawing the view. This needs to be done because otherwise the old graphics may interfere and it looks ugly. The redraw should sharpen the draw lines too.
you set your cell's frame to be positioned somewhere else (here 200,200) but it is completely normal that it has no effect. A cell cannot be elsewhere than CGPointZero. If you like to displace it, you have to create a bigger view and move the content. (the view can be translucent but it will slow down the scrolling on older devices dramatically)
you ask why you don't have to redraw each cells but only the tableView. Actually I don't know this exactly but it should be in fact of the frame change of the table view. Normally a frame change occur by rotating the device so that the width changes. Now it would be pretty stupid for a developer to update each cell for the new size. Thanks to Apple the tableView calls the necessary update request for each cell which is visible on screen. Eventually the same methods are called for all views: drawRect:
I have problems understanding all your problems but will do my best.
When you rotate the device, the table view size changes (the frame). So you have to set the new frame for the table view to accomplish the new "design" (stretching the table view to the whole width). This is not true for the cells, because they stay at the same size even after the rotation.
an example:
________
|______| -> a cell width: 50 height: 200
after rotation:
___
| |
| | -> still the same size, width: 50 height: 200
|_|
a CGAffineTransform is only a visual effect. It has no impact on the size neither the position of its subviews. So you have to do the exact opposite rotation for your cells then for your table view. In which direction is it wrong rotated? upside-down, left, right, or do you use an edge for rotating so that the rotation point is wrong chosen?
I would like to have a tablew view with a behaviour similar to the iPhone Contacts app by Apple: a uitableviewcell with a uitextview inside, so that when I write in the uitextview, the uitextview increases its height, and so accordingly the uitableviewcell dynamically adjusts its height. I searched over the whole web, finding only partial solutions and lack of sample code!
please help me I am desperate
Tony
Looking at this,you need to be somewhat tricky. You need to calculate the height of the textView dynamically and based on the Height of the TextView,you need to return the Height for the cell..
It's very easy & somewhat Tricky..
This is the code by which you can calculate the size of string....
First get the size of String
NSString *label = #"Sample String to get the Size for the textView Will definitely work ";
CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
constrainedToSize:CGSizeMake(320, 9999)
lineBreakMode:UILineBreakModeWordWrap];
over here ....
NSLog(#"%f",stringSize.height);
Secondly dynamically create the textView in the cell..giving the stringSize.height
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//}
NSDictionary *d=(NSDictionary *)[self.menuArray objectAtIndex:indexPath.section];
NSString *string = [d valueForKey:#"Description"];
CGSize stringSize = [string sizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap];
UITextView *textV=[[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, stringSize.height+10)];
textV.font = [UIFont systemFontOfSize:15.0];
textV.text=string;
textV.textColor=[UIColor blackColor];
textV.editable=NO;
[cell.contentView addSubview:textV];
[textV release];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *d=(NSDictionary *)[self.menuArray objectAtIndex:indexPath.section];
NSString *label = [d valueForKey:#"Description"];
CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
constrainedToSize:CGSizeMake(320, 9999)
lineBreakMode:UILineBreakModeWordWrap];
return stringSize.height+25;
}
After giving so much pain to my fingers,......I think this is enough code...& will surely help to solve your problem..
Good Luck
Create a custom UITableViewCell and add your UITextView to the cell's contentView.
In LayoutSubviews, set textView.frame to the cell's contentView.bounds (or do some other custom layout).
When the textView contents change (discovered via UITextViewDelegate), do two things:
1) call [tableView beginUpdates]; [tableView endUpdates]; This will force the table view to recalculate the height for all cells (will call tableView:heightForRowAtIndexPath:). If your cell is the delegate for the textView then you'll have to figure out how to get a pointer to the tableView, but there are a few ways to achieve that. Or you could make the delegate your view controller...
2) when tableView:heightForRowAtIndexPath: is called for this cell, return the textView.contentSize.height. You can get your cell from here by calling [tableView cellForRowAtIndexPath]; Or if you just have one of these cells then cache a pointer to it in your viewController.
The only issue I found with the accepted answer was that we are allocating the UITextView each and every time. I found that this raised issues with typing into the view and having the text updating immediately and also keeping the view as first responder. When I tried to reload the cell with the new height it would then try to add a new textView.
Because of this I found a slightly different method to achieve the same goal. Hopefully this different take might help people who are struggling to implement the above code.
1) In the header file define a variable for the height of the text and the textView:
UITextView * _textView;
NSInteger _textHeight;
Setting a variable means that we can load the view to be a certain height if we are loading text into the textView and also reduces the complexity.
2) Load the text view and add it to our cell
_textView = [[UITextView alloc] init];
_textView.delegate = self;
_textView.returnKeyType = UIReturnKeyDone;
_textView.font = [UIFont fontWithName:#"Helvetica" size:16];
if (![_user metaStringForKey:bBioKey].length) {
_textView.text = #"Placeholder text";
_textView.textColor = [UIColor lightGrayColor];
}
- (UITableViewCell *)tableView:(UITableView *)tableView_ cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath == 0) { // Add logic to choose the correct cell
if (_textView.superview != cell) {
[cell addSubview:_textView];
_textView.keepTopInset.equal = KeepRequired(7);
_textView.keepBottomInset.equal = KeepRequired(7);
_textView.keepRightInset.equal = KeepRequired(10);
_textView.keepLeftInset.equal = KeepRequired(70);
}
}
}
}
Using keeplayout has enabled us to keep our textfield to always stay the same height as the cell. We are also only ever adding our UITextView once.
3) Add the code to calculate the height of the text
- (NSInteger)getHeightOfBio: (NSString *)text {
UILabel * gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:#"Helvetica" size:16];
gettingSizeLabel.text = text;
gettingSizeLabel.numberOfLines = 0;
CGSize maximumLabelSize = CGSizeMake(240, 9999); // this width will be as per your requirement
CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];
return expectedSize.height;
}
I have tried many and found this to work the best
4) Add some logic in the cell height to make use of this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) { // Set the height for our changing textView
return 30 + [self getHeightOfBio:_textView.text];
}
return 44;
}
Obvious we need a bit more height than our text height so I added an extra cushion amount which can be experimented with.
5) Refresh the view each time a character is typed to check if we need to increase the size:
- (void)textViewDidChange:(UITextView *)textView {
if ([self getHeightOfText:textView.text] != _textHeight) {
_textHeight = [self getHeightOfText:textView.text];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
In this section we get the height of the text each time the user types.
Then though we use our stored value and compare the current value to the stored value. Obviously if they are the same then there is no point in refreshing the view. If they are different we update the value and then refresh our table.
This bit I found a good answer on stackOverflow showing how we can refresh only the heights of the table instead of the cell itself. Why refresh the cell when we don't need to? This means that once this is called the cell height is updated and it increases nicely.
Anyway I found this worked really nicely and was simple enough that it can be put together or have different parts taken and put into other peoples pieces of code.
Props to the accepted answer which was pillaged for various pieces along the way but I also hope that this answer helps some people who are having the same difficulties that I had.
Finally I got it working. The main problem is how to get cell's contentView correct width. Hardcoded width does not work for all cases since it may vary accordingly plain/grouped table style, added accessories, or landscape/portrait layout. The only way to get 100% correct width is to ask it from cell object. So I create cell right in heightForRowAtIndexPath and store it in cache, then this cached cell will be returned by cellForRowAtIndexPath method.
Another problem is how to force cell to layout its subviews before it is used. It can be done if we temporary add cell to the tableView and update cell's frame with tabelView's width. After that all subviews will be layouted in the right way. Here is how I got it working in my TableKit library.
I've written up my learnings and solution for calculating the UITableViewCell height based on an inner UITextView on my blog. The post contains the code that works for universal apps, both table view styles and autorotation.
I edit TomSwift response which is the best way to do it :
here is my cell code (in swift)
class CommentaireTextViewCell: UITableViewCell,UITextViewDelegate {
#IBOutlet weak var textViewCom: UITextView!
weak var parentTableView:UITableView?
#IBOutlet weak var constraintTextViewTopMargin: NSLayoutConstraint!
#IBOutlet weak var constraintTextViewHeight: NSLayoutConstraint!
#IBOutlet weak var constraintTextViewBottomMargin: NSLayoutConstraint!
override func awakeFromNib() {
self.textViewCom.delegate = self;
}
func textViewDidChange(textView: UITextView) {
self.parentTableView?.beginUpdates();
self.parentTableView?.endUpdates();
}
func getHeight() -> CGFloat
{
constraintTextViewHeight.constant = self.textViewCom.contentSize.height;
// cell height = textview marge top+ textview height+ textView Marge bottom
return constraintTextViewTopMargin.constant+constraintTextViewHeight.constant+constraintTextViewBottomMargin.constant+8
// add 8 because it seems to have an inset inside the textView
}
override func setSelected(selected: Bool, animated: Bool) {
self.textViewCom.becomeFirstResponder();
}
}
for the explaination, the cell table view is a weak propertie of the cell so I can tell it to update layout when user enter text.
The height of the cell is the sum of its top constraint to the contentView, its bottom constraint to the contentView and the textView.contantSize.height which is also equal to the textView constant height
You need to return the correct height in the heightForRowAtIndexPath delegate method.
Try the following code:
CGSize constraintSize;
constraintSize.height = MAXFLOAT;
constraintSize.width = yourTextView.frame.size.width;
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"yourFontName" size:yourFontSize], NSFontAttributeName,
nil];
CGRect frame = [yourTextView.text boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesDictionary
context:nil];
CGSize stringSize = frame.size;//The string size can be set to the UITableViewCell
you can get the UITextView size programmatically.According to the size,set the height of the cell using the following delegate
tableView:heightForRowAtIndexPath:
Guys this is really cool stuff but you can use tableview:didSelectRowForIndexPath: to add the UITextView to the cell as it's subview when the user taps it, works very well since you need to use only 1 UITextView which you can reuse and won't interfere with the tableview receiving touches! Release it when done.
Details? just ask!
I added the interfaceOrientation to my app. It works fine concerning the views. Some of the table-cells I defined by CGRects to position the text in the cell. In portrait-mode the cell is 300px long, in landscape-mode 420px. I use the following code to change the CGRects depending the orientation:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.interfaceOrientation == UIDeviceOrientationPortrait) {
NSString *currentLanguage = [[NSString alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"/Documents/sprache.txt"]];
static NSString *TableViewTableCellIdentifier = #"TableViewTableCellIdentifier";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:TableViewTableCellIdentifier];
CGRect cellRect = CGRectMake(0, 0, 300, 175);
cell.backgroundColor = [UIColor darkGrayColor];
cell = [[[UITableViewCell alloc] initWithFrame:cellRect reuseIdentifier:TableViewTableCellIdentifier] autorelease];
CGRect keyLabelRect = CGRectMake(0, 5, 5, 20);
UILabel *keyLabel = [[UILabel alloc]initWithFrame:keyLabelRect];
keyLabel.tag = 100; //.........
} else {
NSString *currentLanguage =
[[NSString alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"/Documents/sprache.txt"]];
static NSString *TableViewTableCellIdentifier = #"TableViewTableCellIdentifier";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:TableViewTableCellIdentifier];
CGRect cellRect = CGRectMake(0, 0, 450, 175);
cell.backgroundColor = [UIColor darkGrayColor];
cell = [[[UITableViewCell alloc] initWithFrame:cellRect reuseIdentifier:TableViewTableCellIdentifier] autorelease];
CGRect keyLabelRect = CGRectMake(0, 5, 5, 20);
UILabel *keyLabel = [[UILabel alloc] //.....
}
}
My problem is, when the table is visible and the orientation is changed, I need to scroll to see the new "layout". How can I manage to "reload" the view after changing the orientation?
First of all, this will leak like mad. You create cells and dequeue them but you never release them. You just create an entirely new cell every time a cell is requested. There is no reason to recreate a cell if you dequeue and vice versa. More importantly, your creating as many cells as you have rows in your logical table. That will eat all your memory very quickly.
When you dequeue a cell, you need to check if it's frame is the right size and reuse it if it is. If it is not, then you need to release the cell and create another one.
Second, a table will not ask for new cells until you scroll the existing cells off the screen. This is why your cells do not change until you scroll. It's the expected behavior of a tableview.
My standing recommendation for any moderately complex view is to use different view-controller/view pairs for each orientation. It seems like more work but usually I find it it actually takes less and it's easier to manage. In this case, having two separate tables will probably save you a lot of grief.
I'm pretty sure that you do not need to specify frame during default UITableViewCell construction. Usually frame size is handled by UITableView itself.
But if you wish you can send setNeedsLayout and/or setNeedsDisplay message to a tableView to force it update cell layout (in a orientation handler).