Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align cells to bottom and top of UITableView, leaving stretchable gap in middle

I have a table view with five cells displaying the settings of my app. I want the first four cells to appear at the top. The last cell isn't actually a setting, it says "Legal" and takes you to the EULA, so I want it to appear at the bottom.

Now I know I could use – tableView:viewForHeaderInSection: and– tableView:heightForHeaderInSection: to create some padding, but I really don't like hardcoding in dimensions this way. I also don't want to use UIButton, because I want it to be exactly the same style as the rest of the cells.

Does anyone know the best practice for going about this?

like image 645
jamesmoschou Avatar asked Mar 05 '10 06:03

jamesmoschou


1 Answers

I'm assuming you're using a grouped table view, like the settings app. What I've done is created a group section between the top and bottom group sections, to which I've add a 'transparent' row cell, that I size dynamically.

I've created a simple demo for you using hardcoded values, but hopefully you'll get the idea. Obviously you would get the number of sections and the number of rows from your data structure:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 3; 
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    int rtn = 0;

    if (section == 0)
        rtn = 4;
    else if (section == 1)
        rtn = 1;
    else if (section == 2)
        rtn = 1;

    return rtn;
}

/*
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 44.0f;
}
*/

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    int TOTALCELLS = 6;
    float CONSTANT = 0.5f;

    if (indexPath.section == 1) 
        return  self.view.frame.size.height - (44.0f * (CONSTANT + TOTALCELLS));

    return 44.0f;
}



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];

    }



    if (indexPath.section == 0) 
    {
        if (indexPath.row == 0) {

            cell.textLabel.text = @"My Switch";
            UISwitch *boolSwitch = [[UISwitch alloc]initWithFrame:CGRectZero];
            boolSwitch.on =  YES;
            [cell setAccessoryView:boolSwitch];
            [boolSwitch release];

        } else if (indexPath.row == 1) {

            cell.textLabel.text = @"My TxtField";
            [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
            UITextField *txtField = [[UITextField alloc]initWithFrame:CGRectMake(0,0,175,20)]; 
            txtField.text =  @"Default Value";
            txtField.textColor = [UIColor darkGrayColor];
            [txtField setClearButtonMode:UITextFieldViewModeAlways];
            [cell setAccessoryView:txtField];
            [txtField release];

        } else if (indexPath.row == 2) {

            cell.selectionStyle=UITableViewCellSelectionStyleNone;
            UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0,0,280,22)];
            slider.minimumValue  = 0.0f;
            slider.maximumValue = 10.0f;
            slider.value =  0.7f;
            slider.minimumValueImage = [UIImage imageNamed:@"minus.png"];
            slider.maximumValueImage = [UIImage imageNamed:@"plus.png"];
            [cell setAccessoryView:slider];
            [slider addTarget:self action:@selector(sliderChange:forEvent:) forControlEvents:UIControlEventValueChanged];
            [slider release];

        } else if (indexPath.row == 3) {

            cell.textLabel.text = @"My MultiValue";
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
            cell.detailTextLabel.text = @"Default selection";
        }

    } else if (indexPath.section == 1) {

        UIView *transCell = [[UIView alloc] initWithFrame:CGRectZero];
        transCell.backgroundColor = [UIColor clearColor];
        cell.backgroundView = transCell; 
        [transCell release];
        [cell setSelectionStyle:UITableViewCellSelectionStyleNone];

    } else if (indexPath.section == 2) {

        cell.textLabel.text = @"Legal";
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }



    return cell;
}

The critical parts are in cellForRowAtIndexPath, where the transparent row is created. The trick here is to add the transparent view to the cell's backgroundView, and set the cell selection style to None.

UIView *transCell = [[UIView alloc] initWithFrame:CGRectZero];
transCell.backgroundColor = [UIColor clearColor];
cell.backgroundView = transCell; 
[transCell release];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

and in heightForRowAtIndexPath, the dynamic sizing of the transparent row.

self.view.frame.size.height - (44.0f * (CONSTANT + TOTALCELLS));

TOTALCELLS is the total of all of the cells, including the transparent one. You may need to do additional work on this algorithm, as it doesn't take into consideration what happens when number of cells grows beyond what is visible, and I haven't tested it with various combinations of navigation and toolbars.

I hope this works for you.

Valid XHTML

like image 145
Gene Myers Avatar answered Oct 26 '22 23:10

Gene Myers