I created a new Single-view project (using storyboard) in Xcode with a single UITableViewController. Here is the setup code:
- (void)viewDidLoad {
[super viewDidLoad];
_footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
_footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, 44, 44)];
l.text = #"Label Label Label Label Label Label Label Label Label";
l.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
l.backgroundColor = [UIColor clearColor];
[_footerView addSubview:l];
_footerView.backgroundColor = [UIColor lightGrayColor];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return _footerView.frame.size.height;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return _footerView;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [tableView dequeueReusableCellWithIdentifier:#"Cell"];
}
I want the label in the custom table footer view to be drawn at x = 60, but when I run the project, at first the label is invisible (in portrait, screen attached). Then if I rotate once, it becomes visible and if I rotate back to portrait it's visible.
What am I missing?
You seem to be initialising your footer view with a width and height of 44px, yet adding the label outside of its bounds.
Try the following instead:
_footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.tableView.frame), 44)];
_footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
UILabel *l = [[UILabel alloc] initWithFrame:CGRectInset(_footerView.bounds, 60.0f, 0.0f)];
l.text = #"Label Label Label Label Label Label Label Label Label";
l.autoresizingMask = UIViewAutoresizingFlexibleWidth;
l.backgroundColor = [UIColor clearColor];
[_footerView addSubview:l];
_footerView.backgroundColor = [UIColor lightGrayColor];
As a further point, try not to use [UIColor clearColor] as a label background colour if you can help it - it significantly reduces scrolling performance. In this case you should use [UIColor lightGrayColor] so it matches its superview.
Related
I have added footerview programmatically for each section as follows. I could able to see the footerview.
However, when I scroll up or down at the bottom or at the top of the tableview, footerview overlays on top of tableviewcells.
How could I able to disable it?
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if(adminOrderElements[section].expanded && [adminOrderElements[section].notes length]>0)
{
return 60;
} else {
return 0;
}
return 60;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *footer = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 60)];
footer.backgroundColor = [UIColor clearColor];
UILabel *lbl = [[UILabel alloc]initWithFrame:footer.frame];
lbl.backgroundColor = [UIColor clearColor];
lbl.text = #"Your Text";
lbl.textAlignment = NSTextAlignmentCenter;
[footer addSubview:lbl];
return footer;
}
Before Scroll
After Scroll
If I understand your question correctly, you only have to change the UITableViewStyle to UITableViewStyleGrouped. According to the docs, for table views using grouped style the section headers and footers do not float.
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.
In the screenshot below, the blue colored line is the header and footer of the sections of my tableView (In the tableView, I am treating rows as sections).
However, i want the blue line to be just below the row of the tableView (of same width as the row). Any idea how to do it??
-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 333, 1)] ;
headerView.backgroundColor = [UIColor blueColor];
return headerView;
}
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 333, 1)] ;
footerView.backgroundColor = [UIColor blueColor];
return footerView;
}
You can add UIView with Blue color above the UIView for which set the background color to Clear Color
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
UIView *dummyfooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 2)] ;
dummyfooterView.backgroundColor = [UIColor clearColor];
// Widht should be less than dummyfooterView
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(10, 0, 320-20, 2)] ;
footerView.backgroundColor = [UIColor blueColor];
[dummyfooterView addSubview:footerView];
return dummyfooterView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 2;
}
I am not sure though, hope this may help you! The output will be like below screen. I have used Grouped tableview style here.
I think the best way is to add 1px view at bottom of cell at row at indexpath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MessageBoxCell";
LGMessageBoxCell *cell = (LGMessageBoxCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.fram.size.height - 1, cell.fram.size.width, 1)] ;
headerView.backgroundColor = [UIColor blueColor];
cell.backgroundView = headerView;
return cell;
}
Set height for header and fooder
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 58;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 58;
}
I used the following code to set the header view of a uitableview section. The problem is, the background color (mainLightColor_2) doesn't show up until I scroll the tableview. How can I make the background color shown on load?
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 24)];
headerView.backgroundColor = [Utility mainLightColor_2]; //mainLightColor is a blue color
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 2, 200, 20)];
label.backgroundColor = [UIColor clearColor];
label.textColor = [Utility mainDarkColor];
label.text = #"Past Activities";
[headerView addSubview:label];
return headerView;
}
Before scroll:
After scroll:
You should also implement - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section method.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 24;
}
So I found a solution to this. However, I still don't understand why setting the background color of headerView doesn't work.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 24)];
UIView *headerViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 24)];
headerViewBackground.backgroundColor = [Utility mainLightColor_2];
[headerView addSubview:headerViewBackground];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 2, 200, 20)];
label.backgroundColor = [UIColor clearColor];
label.textColor = [Utility mainDarkColor];
label.text = #"Past Activities";
[headerView addSubview:label];
return headerView;
}
Im a bit stuck trying to create a custom ios table header. My headers are 30px tall and I am using this code to create them:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
if (sectionTitle == nil) {
return nil;
}
// Create label with section title
UILabel *label = [[UILabel alloc] init] ;
label.frame = CGRectMake(0, 0, 140, 30);
label.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"header_gradient.png"]];
label.textColor = [UIColor whiteColor];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake(0.0, 1.0);
label.font = [UIFont boldSystemFontOfSize:12];
label.text = sectionTitle;
// Create header view and add label as a subview
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 140, 30)];
[view addSubview:label];
return view;
}
- (CGFloat)tableView:(UITableView *)tableViewheightForHeaderInSection:(NSInteger)section {
return 30;
}
It almost works, but my headers seem to colide with the cells/headers below them:
Can anyone point me in the right direction on cleaning up the headers here?
Thanks in advance
You're missing a [space]:
You have:
- (CGFloat)tableView:(UITableView *)tableViewheightForHeaderInSection:(NSInteger)section {
It should be:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {