Envin
Envin

Reputation: 1523

Should I redesign this implementation or can I dynamically add cells to a StaticTableViewController

I have a contacts application and I have a view where the user can click to see "detailed" information on the user. In this detailed view, it will ONLY show fields that have a value, and hide the rest. When the user clicks "Edit", it will show ALL fields to allow the user to edit.

Let me show some screens of this

Detailed View with hidden rows

Edit View

I am using a third party StaticDataTableViewController class to hide and show cells.

Here is my actual question I made this post where I asked how to handle emails and phone numbers more dynamically instead of defining "work email", "home email", "work phone", "home phone".

I need to figure out a way to display and represent dynamically generated emails / phone numbers. If the user has 5 phone numbers, then I want to show 5 phone numbers plus their label (home,work). I will have all of these stored in an NSArray of NSDictionaries (key = label, value = email / phone) and there will be two of those NSArrays per contact.

I just need some assistance on how to be dynamic and static at the same time? I don't want to lose the functionality of hiding cells.

I will paste the class that handles my table view.

SingleContactViewController.h

#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
#import "PublicContactsViewController.h"
#import "Person.h"
#import "SingleContactTableViewCell.h"
#import "StaticDataTableViewController.h"
#import "DTAlertView.h"

@interface SingleContactViewController : StaticDataTableViewController <UITextFieldDelegate,UIAlertViewDelegate>

@property (nonatomic, strong) Person *person;
@property (strong, nonatomic) IBOutlet UIBarButtonItem *editButton;

// TextFields are embedded in the cell, was just easier to make an outlet
@property (strong, nonatomic) IBOutlet UITextField *firstNameTextField;
@property (strong, nonatomic) IBOutlet UITextField *lastNameTextField;
@property (strong, nonatomic) IBOutlet UITextField *homeEmailTextField;
@property (strong, nonatomic) IBOutlet UITextField *workEmailTextField;
@property (strong, nonatomic) IBOutlet UITextField *companyNameTextField;
@property (strong, nonatomic) IBOutlet UITextField *homePhoneNumberTextField;
@property (strong, nonatomic) IBOutlet UITextField *workPhoneNumberTextField;
@property (strong, nonatomic) IBOutlet UITextField *cellPhoneNumberTextField;

// Outlet to cells to hide/unhide
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *firstNameCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *lastNameCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *homeEmailCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *workEmailCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *companyNameCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *homePhoneNumberCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *workPhoneNumberCell;
@property (weak, nonatomic) IBOutlet SingleContactTableViewCell *cellPhoneNumberCell;
@property (strong, nonatomic) IBOutlet SingleContactTableViewCell *deleteContactCell;


- (IBAction)deleteContact:(UIButton *)sender;

@end

SingleContactViewController.m

#import "SingleContactViewController.h"
#import "Person.h"

@interface SingleContactViewController ()

//@property (strong, nonatomic) IBOutlet ADBannerView *banner;
@property (nonatomic, assign) BOOL isEditing;
- (IBAction)popBackToContacts:(UIBarButtonItem *)sender;
- (IBAction)editContact:(UIBarButtonItem *)sender;


@end


@implementation SingleContactViewController

#pragma mark - Lifecycle methods

- (void)viewWillAppear:(BOOL)animated
{
    self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:.498 green:0 blue:.0 alpha:1];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.firstNameTextField.delegate = self;
    [self populateFieldsAndHideEmptyCells];

    //Disable the highlight effect of clicking a table row
    [self.firstNameCell setSelectionStyle:UITableViewCellSelectionStyleNone];
    [self.lastNameCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.homeEmailCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.workEmailCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.companyNameCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.homePhoneNumberCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.workPhoneNumberCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.cellPhoneNumberCell setSelectionStyle:UITableViewCellEditingStyleNone];
    [self.deleteContactCell setSelectionStyle:UITableViewCellEditingStyleNone];

    [self.tableView setBackgroundColor:[UIColor lightGrayColor]];
}

#pragma mark - Editing Methods

- (IBAction)editContact:(UIBarButtonItem *)sender {
    NSLog(@"User pressed 'Edit' button. Entered editContact method");
    if ([self isEditing]) {
        NSLog(@"Turning edit more off");
        UIBarButtonItem *newButton = [[UIBarButtonItem alloc]initWithTitle:@"Edit" style:UIBarButtonSystemItemDone target:self action:@selector(editContact:)];
        self.navigationItem.rightBarButtonItem = newButton;
        _editButton = newButton;
        [self updatePrivateContact];
        self.isEditing = NO;
    }
    else {
        NSLog(@"Turning edit mode on");
        UIBarButtonItem *newButton = [[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonSystemItemEdit target:self action:@selector(editContact:)];
        self.navigationItem.rightBarButtonItem = newButton;
        _editButton = newButton;
        self.isEditing = YES;
        [self showAllFieldsForEditing];

    }
}

#pragma mark - Hide/Show Table Cells

- (void)populateFieldsAndHideEmptyCells
{

    self.hideSectionsWithHiddenRows = YES;

    if([self.person.firstName length] == 0){
        NSLog(@"firstName not present. Hide Cell");
        [self cell:self.firstNameCell setHidden:YES];
    }else{
        self.firstNameTextField.text = [self.person firstName];
        [self.firstNameTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.firstNameTextField setEnabled:NO];
    }

    if([self.person.lastName length] == 0){
        NSLog(@"lastName not present. Hide Cell");
        [self cell:self.lastNameCell setHidden:YES];
    }else{
        self.lastNameTextField.text = [self.person lastName];
        [self.lastNameTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.lastNameTextField setEnabled:NO];
    }

    if([self.person.companyName length] == 0){
        [self cell:self.companyNameCell setHidden:YES];
    }else{
        self.companyNameTextField.text = [self.person companyName];
        [self.companyNameTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.companyNameTextField setEnabled:NO];
    }

    if([self.person.homeEmail length] == 0){
        [self cell:self.homeEmailCell setHidden:YES];
    }else{
        self.homeEmailTextField.text = [self.person homeEmail];
        [self.homeEmailTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.homeEmailTextField setEnabled:NO];
    }

    NSLog(@"person.workemail: %@",[self.person workEmail]);
    if([self.person.workEmail length] == 0){
        [self cell:self.workEmailCell setHidden:YES];
    }else{
        self.workEmailTextField.text = [self.person workEmail];
        [self.workEmailTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.workEmailTextField setEnabled:NO];
    }

    if([self.person.homePhone length] == 0){
        NSLog(@"home phone field not present. Hide Cell");
        [self cell:self.homePhoneNumberCell setHidden:YES];
    }else{
        self.homePhoneNumberTextField.text = [self.person homePhone];
        [self.homePhoneNumberTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.homePhoneNumberTextField setEnabled:NO];
    }

    if([self.person.workPhone length] == 0){
        NSLog(@"work phone field not present. Hide Cell");
        [self cell:self.workPhoneNumberCell setHidden:YES];
    }else{
        self.workPhoneNumberTextField.text = [self.person workPhone];
        [self.workPhoneNumberTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.workPhoneNumberTextField setEnabled:NO];
    }

    if([self.person.cellPhone length] == 0){
        NSLog(@"cell phone field not present. Hide Cell");
        [self cell:self.cellPhoneNumberCell setHidden:YES];
    }else{
        self.cellPhoneNumberTextField.text = [self.person cellPhone];
        [self.cellPhoneNumberTextField setClearButtonMode:UITextFieldViewModeNever];
        [self.cellPhoneNumberTextField setEnabled:NO];
    }

    [self cell:self.deleteContactCell setHidden:YES]; // Only show on Edit

    [self reloadDataAnimated:YES];

}

- (void) showAllFieldsForEditing
{
    NSLog(@"showAllFieldsForEditing method entered");
    self.hideSectionsWithHiddenRows = NO;

    [self cell:self.firstNameCell setHidden:NO];
    [self cell:self.lastNameCell setHidden:NO];
    [self cell:self.companyNameCell setHidden:NO];
    [self cell:self.homeEmailCell setHidden:NO];
    [self cell:self.workEmailCell setHidden:NO];
    [self cell:self.homePhoneNumberCell setHidden:NO];
    [self cell:self.workPhoneNumberCell setHidden:NO];
    [self cell:self.cellPhoneNumberCell setHidden:NO];
    [self cell:self.deleteContactCell setHidden:NO];

    [self.firstNameTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.lastNameTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.companyNameTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.homeEmailTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.workEmailTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.homePhoneNumberTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.workPhoneNumberTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];
    [self.cellPhoneNumberTextField setClearButtonMode:UITextFieldViewModeUnlessEditing];

    [self.firstNameTextField setEnabled:YES];
    [self.lastNameTextField setEnabled:YES];
    [self.companyNameTextField setEnabled:YES];
    [self.workEmailTextField setEnabled:YES];
    [self.homeEmailTextField setEnabled:YES];
    [self.homePhoneNumberTextField setEnabled:YES];
    [self.workPhoneNumberTextField setEnabled:YES];
    [self.cellPhoneNumberTextField setEnabled:YES];

    [self reloadDataAnimated:YES];
}

#pragma mark - Navigation Methods
- (IBAction)popBackToContacts:(UIBarButtonItem *)sender
{
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark - Table View Methods

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

#pragma mark - Update Edit Data
- (void)updatePrivateContact
{
    // Logic here to save to database
}

#pragma mark - Helper Methods

- (BOOL)isAnyEmailPresent
{
    if([self.person homeEmail] != nil || [self.person workEmail] != nil){
        return YES;
    }else{
        return NO;
    }
}

- (Person *)populatePersonToSave
{
    Person *person = [[Person alloc] init];


    person.firstName = self.firstNameTextField.text;
    person.lastName = self.lastNameTextField.text;
    person.workEmail = self.workEmailTextField.text;
    person.homeEmail = self.homeEmailTextField.text;
    person.companyName = self.companyNameTextField.text;
    person.homePhone = self.homePhoneNumberTextField.text;
    person.workPhone = self.workPhoneNumberTextField.text;
    person.cellPhone = self.cellPhoneNumberTextField.text;

    return person;
}

#pragma mark - Table View Methods
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

    cell.backgroundColor = [UIColor lightGrayColor];
    cell.textLabel.textColor = [UIColor whiteColor];
}

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    // Set the text color of our header/footer text.
    UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
    [header.textLabel setTextColor:[UIColor whiteColor]];

    // Set the background color of our header/footer.
    header.contentView.backgroundColor = [UIColor lightGrayColor];

    // You can also do this to set the background color of our header/footer,
    //    but the gradients/other effects will be retained.
    // view.tintColor = [UIColor blackColor];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForHeaderInSection:section];
    }
}

@end

Upvotes: 0

Views: 198

Answers (1)

The Lazy Coder
The Lazy Coder

Reputation: 11818

after looking over the code. The StaticDataTableViewController uses the tableview to display the cells you want it to display based on their own "OriginalRow" class.

These are held in a Mutable Array within their "OriginalSection" class under the property "rows".

The original sections are held in a mutable array on the "OriginalTable" class under a property called "sections"

The original table is your main definition for what your table should contain, and is held on the "StaticDataTableViewController" under a property called "originalTable"

All of the Business of determining what cells to show and what cells to hide is done in "-[OriginalTable prepareUpdates]" which iterates through the sections and each row within to determine what to show and what to hide.

The "-[OriginalTable sections]" array and "-[OriginalSection rows]" arrays continue to contain all sections and rows respectively regardless of their visibility or invisibility, therefore if you edit those arrays and call "-[StaticDataTableViewController reloadData]" you will obtain the actions you are looking for.

To accomplish this you will need to move the "@interface" for each class to the header so you will have access to it.

when you have moved the "@interface" for OriginalRow, OriginalSection and OriginalTable to the header, you are most of the way there.

The last thing to do is move the property from the private category for StaticDataTableViewController to the public interface.

@interface StaticDataTableViewController ()

@property (nonatomic, strong) OriginalTable * originalTable; // Cut this line.

@end

take the marked line and move it to the header in the public interface to make it a public property

@interface StaticDataTableViewController : UITableViewController // Paste after this line

After you have made those changes you should be able to add and remove Sections and Rows at will.

[[[[ThisStaticTable.originalTable sections] objectAtIndex:0] rows] 
                  insertObject:myNewOriginalRow atIndex:2];
[ThisStaticTable reloadData];

This should get you well on your way.

Upvotes: 1

Related Questions