I've implemented a custom viewForHeaderInSection as follows:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
CGRect sectionFrame = CGRectMake(0, 0, tableView.bounds.size.width, 30.0f);
float xInset = 16.0;
RTUTableHeaderView
*headerView =
[[RTUTableHeaderView alloc] initWithFrame:sectionFrame
andBackgroundColor:[UIColor clearColor]
FontColor:[RTUColorHelper kSettingsTableCellFontColor]
andFontSize:18.f
withLabelFrame:CGRectMake(xInset, 10.f, sectionFrame.size.width - xInset, 20)];
headerView.label.text = [self tableView:tableView titleForHeaderInSection:section];
return headerView;
}
This pushes the labels down by 10pts so that they sit closer to the relevant section. In iOS6 it looks fine, but for iOS7 the label in the first section header is around 10pts further up than the others. If I take away the 10pt offset, the label for the first section sits at the top of the headerView whereas the others are vertically-centered in their header frames.
I could just frig the values for section 0 if it's a bug but would obviously rather not and wanted to check that I haven't forgotten something else or done something wrong.
The section headers are all the same height, heightForRowAtIndexPath returns 44.f
So the only way I managed to fix this problem was to add an offset to the first section header:
if(section==0){
CGRect labelFrame = headerView.label.frame;
labelFrame.origin.y+=15.f;
[headerView.label setFrame:labelFrame];
}
If anyone has any better ideas I'd love to hear them!
Related
UITableview cells are returning heights that don't really correlate to their text.
I have been dealing with a rather annoying bug where xcode returns incorrect heights for cells and just in general is return pixels heights for elements in cells that are terribly inconsistent.
I thought I could implement the methods below to clean things up, but they turned out just to make things worse.
The first image in the google doc is what my cells look like when I use these methods. Please tell me any ideas you have to fix them. The crux of the problem is a special case which I have shown in the second image of the google doc.
The reason behind the special case and a deeper discussion of the reason it occurs is in the google doc. Here's the google doc link:
https://docs.google.com/document/d/1tT43nE-1Wq8leRIaoQ29S0aQhZUWP88kIX3WlG_RcOg/edit?usp=sharing
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section==0) { //postcell
return 500.0; //TODO add some autolayout stuff for this case...
} else { //comment cell
UIFont * font=[UIFont fontWithName:#"Helvetica Neue" size:13.0];
NSIndexPath *adjustedIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section-1];
BRComment *comment = [self.commentsController objectAtIndexPath:adjustedIndexPath];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
//CommentCell * commentCell=(CommentCell *)[self.tableView cellForRowAtIndexPath:indexPath];
CGSize labelHeight = [self heigtForCellwithString:comment.body andLabelWidth:screenWidth-78.0 withFont:font];
return labelHeight.height; // the return height + your other view height
}
}
-(CGSize)heigtForCellwithString:(NSString *)stringValue andLabelWidth:(CGFloat)labelWidth withFont:(UIFont *)font{
CGSize constraint = CGSizeMake(labelWidth,9999); // Replace 300 with your label width //TODO replace
NSDictionary *attributes = #{NSFontAttributeName: font};
CGRect rect = [stringValue boundingRectWithSize:constraint
options: (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:attributes
context:nil];
return rect.size;
}
iOS 8 introduces the super handy UITableViewAutomaticDimension const to UITableView. To get cells to size themselves automatically simply return UITableViewAutomaticDimension from both -tableView:heightForRowAtIndexPath: and -tableView:estimatedHeightForRowAtIndexPath:.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
Voila, your cells should be sized correctly. Note this'll also take into account cell layoutMargins and indentationWidth/indentationLevel if you need to use those.
I cannot get this to work. I am using autolayout on the current view controller. I have a UITableView that has section headers and each section header has UITextView that has text that varies in length depending on the section. I cannot make it enlarge its height automatically to fit the contents so there will be no need for scroll (its contents are attributed text)
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
//UITextView *tv = [[UITextView alloc] init];
//tv.editable = NO;
//tv.attributedText = [self millionaireResults][section][#"header"];
//return tv;
return [self millionaireResults][section][#"headerview"]; //this is a uitextview
}
// this did not workeither
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
UITextView *tv = [self millionaireResults][section][#"headerview"];
return tv.frame.size.height;
}
How can this problem be solved?
I updated the code per the suggestion of Michael below
Make your "UITextView *tv" object a property and then you can do something like this (assuming you only have exactly one section to your table view):
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return (self.tv.frame.size.height);
}
If you have more sections (which is appears you do), you should make that property a NSArray of UITextView objects.
This also means you need to set the contents of your "tv" object before "viewForHeaderInSection:" gets called.
This is the answer that worked for me
When you are creating the UITextView, you must set the scrollEnabled
to false.
Your UITextView must be given the width that covers horizontal space otherwise auto size calculation are off (sometimes it is sometimes it is not, i think depending on wordbreak or something, but it was inconsistent!) and only fixes itself if you rotate the device to force redraw
In the heightForHeaderInSection method, you must get the
sizeThatFits and return its height as the height of your text view
Here is the height calculation (I found this on this site http://www.raywenderlich.com/50151/text-kit-tutorial )
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
UITextView *tv1 = (UITextView *)[self millionaireResults][section][#"headerview"];
// sizethatfits calculates the perfect size for this UITextView
// if you gave your UITextView full width
CGSize goodsize = [tv1 sizeThatFits:tv1.frame.size];
return goodsize.height+4; // here 4 is not necessary, i just put it as an offset
}
Here is the code that creates those UITextView objects
for (int i = 0; i < [milarr count]; i++) {
UITextView *tv = [[UITextView alloc] init];
tv.editable = NO;
tv.attributedText = milarr[i];
// labelTopTitle and this table in question have same width in an autoLayouted view
// so i am giving width of labelTopTitle to let UITextView cover full available
// horizontal space
tv.frame = CGRectMake(0, 0, self.labelTopTitle.frame.size.width,FLT_MAX);
//tv.backgroundColor = [UIColor grayColor];
//tv.textContainerInset = UIEdgeInsetsZero;
tv.scrollEnabled = NO;
[results addObject:#{#"headerview": tv,
#"rows":#[...]
}
];
}
I am trying to set zero padding on collection view cells, I have set "Min Spacing" on the view controller to:
Yet it still has gaps between the cells:
Also I'd like it so that the cells wrap nicely depending on the width of the frame, for example each cell is 50px wide, so if there are six cells and I set the frame width to 150px, it will display two lines of three cells.
Yet if I set the frame width to 150 by doing:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame = self.collectionView.frame;
frame.size.width = 150;
self.collectionView.frame = frame;
}
It looks like in the above screen shot (too wide).
If I set it to something ridiculously small such as 10, it then wraps to some extent:
The UICollectionViewCell is set to 50 x 50:
I have also tried setting the size of the cell programatically, and also removed the UIEdgeInset:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0, 0, 0, 0);
}
I have disabled auto layout just incase that had any interference. Any advice as to how I can remove the padding and also have them wrap depending on the frame width / height?
You are using a UICollectionViewController which, like a UITableViewController, has the collection view (or table view) as the base view property of the view controller. This means it can't be resized from within the view controller; it's size is controlled by its superview - either the window, in this case, which has it as the root view controller, or a parent view controller if you were embedding it.
If you want to reduce the collection view area so the cells abut one another, you can amend the section insets of the collection view in the storyboard. In your case, an inset of 15 left and right brings the cells together - this is 9 * 50 (450) plus 30 = 480 which is the width of a 3.5inch iPhone in landscape.
Obviously this will be different in the iPhone 5 or iPad. You can either calculate the insets at run time, use a collection view held in a standard UIViewController subclass, or hold the UICollectionViewController as an embedded view controller. The latter two will enable you just to specify a size, which is probably nicer than calculating insets.
I am not sure those cells in the screenshot are 50x50 (EDIT: I guess they are...).
Check if you connected the UICollectionViewDelegate and UICollectionViewDataSource.
This it the method you need to implement
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize retval = CGSizeMake(50, 50);
return retval;
}
If it does not work, try putting this code inside viewDidLoad
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[flowLayout setItemSize:CGSizeMake(50.0f, 50.0f)];
[self.collectionView setCollectionViewLayout:flowLayout];
Implement this method in your ViewController
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 2; //the spacing between cells is 2 px here
}
the minimumInteritemSpacing is just that, a minimum value, so it can be larger if the UICollectionViewLayout class decides it needs to be
To correct for this you can create your own layout subclass, and implement the - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath method, something like the answer from this question (see the second question, not the one marked as correct)
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* atts =
[super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item == 0) // degenerate case 1, first item of section
return atts;
NSIndexPath* ipPrev =
[NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat rightPrev = fPrev.origin.x + fPrev.size.width + 10;
if (atts.frame.origin.x <= rightPrev) // degenerate case 2, first item of line
return atts;
CGRect f = atts.frame;
f.origin.x = rightPrev;
atts.frame = f;
return atts;
}
I have a tableview section header, for which I'd like to add a custom view. When the tableview loads, it appears black, shown here: http://postimage.org/image/luluolc57/ When I start scrolling, and the header "sticks" to the top of the screen/navbar, it becomes just how I want it - shown here http://postimage.org/image/lek98nxud/
Basically, I'd like this view to be transparent with this gray tinted circle on it, so the tableview background shows through. here's the respective code.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return [[SummaryView alloc] init];
}
- (void)drawRect:(CGRect)rect
{
CGRect tintSize = CGRectMake(0.0, 0.0, self.bounds.size.height, self.bounds.size.height);
[[UIImage imageNamed:#"Circular Tint.png"] drawInRect:tintSize];
}
Does it work as expected with a standard UILabel?
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UILabel* label = [[UILabel alloc] init];
[label setText:#"TEST"];
return label;
}
If it does, you can slowly try transitioning from that and see at what point the problem arises. It might be related to the size of your custom view when it is alloc and init. Maybe initWithFrame would solve it.
I'm working witha simple tableview but I need to modify the font size for the text in the group header.
I've found this question on stackoverflow eferencing the tableview methods to override but I'm looking for an example of how I might modify the actual headers font size once I implement this method
Note: I'm able to modify the height of the header itself using interface builder but the font size appears to require some objective-c to modify this
Thank you in advance
Edit
here is what I have so far -it's not throwing an exception but the header itself doesn't show the text or font size I set on the label itself
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView* x = tableView.tableHeaderView;
UILabel* y = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, 310, 0)];
y.font = [UIFont boldSystemFontOfSize:12.0];
y.text = #"ha";
[x addSubview:y];
[y release];
return x;
}
The header for a table may be set to any subclass of UIView. In particular, you can create a UILabel, set the text with your desired font size, then make the label the headerView.
Three potential problems with your edit:
Did you remember to implement tableView:heightForHeaderInSection:?
The height of your UILabel is currently 0.
When this method is called, tableView.tableHeaderView may not yet be defined.
My approach would be to declare UILabel *headerLabel and then add this to viewDidLoad:
headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, 310, 15)];
headerLabel.font = [UIFont boldSystemFontOfSize:12.0];
headerLabel.text = #"Testing";
Then have
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 15.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return headerLabel;
}