Custom Tableview, Click on table cell and Expand with another TableView, TableView Search

NSString, UIActivityIndicatorView, UITableView, typedef, NSArray, UIColor, CGFloat, NSDictionary, UISwitch, UIBezierPath, CAShapeLayer, Delegate, UIButton, UILabel, UIView, NSObject, NSJSON

AppDelegate.h

#import “Reachability.h”

@property (nonatomic, retain) Reachability *reachable;

AppDelegate.m

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch.

    

    Reachability *aReachable = [[Reachability alloc] init];

    self.reachable = aReachable;

    self.reachable = [Reachability reachabilityWithHostName: @”apple.com”];

    [self.reachable startNotifier];

    

    return YES;

}

MCCallVendorsController.h

#import “ZJSwitch.h”

@interface MCCallVendorsController : UIViewController

@property (strong, nonatomic) NSString *moveTo;

@property  (strong, nonatomic) NSString *moveFrom;

@property (strong, nonatomic) NSArray *arrayJson;

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;

//@property (weak, nonatomic) IBOutlet UISwitch *switchMoveFromTo;

@property (weak, nonatomic) IBOutlet UIView *viewForSwitch;

MCCallVendorsController.m

#import “MCCallVendorsController.h”

#import “MCCallVendorVendorCell.h”

#import “MCCallVendorVendorModel.h”

#import “MCCallVendorTaskCell.h”

#import “MCCallVendorTaskModel.h”

#import “Utility.h”

//#import “MCNetworkManager.h”

#import “MCVendorsListController.h”

NSString *const filterTaskConstant = @”%K CONTAINS[c] %@”;

NSString *const vendorCell = @”vendorCell”;

NSString *const viewMore = @”viewMore”;

NSString *const taskSectionCell = @”taskSectionCell”;

NSString *const placeholderText = @”Search:moving, packing”;

NSString *const vendorsListControllerName = @”MCVendorsListController”;

typedef enum

{

    MCVendorTypeFrom,

    MCVendorTypeTo

}MCVendorType;

@interface MCCallVendorsController ()<UITableViewDataSource,UITableViewDelegate,MCCallVendorTaskCellProtocol , MCCallVendorVendorCellProtocol,UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *searchTextField;

@property (nonatomic, strong) NSMutableArray *fromModelArray;

@property (nonatomic, strong) NSMutableArray *toModelArray;

@property (nonatomic, strong) NSArray *modelArray;

@property (nonatomic, assign) MCVendorType vendorType;

@property (weak, nonatomic) IBOutlet UITableView *taskVendorsTableView;

@end

@implementation MCCallVendorsController

– (void)viewDidLoad {

    [super viewDidLoad];

    

    

    [self.activityIndicator startAnimating];

    self.navigationController.navigationBarHidden = YES;

    self.vendorType = MCVendorTypeFrom;

    [self loadModels];

    UIColor *color = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];

    self.searchTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholderText attributes:@{NSForegroundColorAttributeName: color}];

    

    

    CGFloat r1 = CGRectGetHeight(self.viewForSwitch.bounds) / 2.0;

    self.viewForSwitch.layer.cornerRadius = r1;

    

    ZJSwitch *switchMoveFromTo = [[ZJSwitch alloc] initWithFrame:CGRectMake(2, 2, self.viewForSwitch.frame.size.width4, self.viewForSwitch.frame.size.height4)];

    switchMoveFromTo.on = NO;

    switchMoveFromTo.backgroundColor = [UIColor clearColor];

    switchMoveFromTo.onTintColor = [UIColor colorWithRed:37/255.0 green:81/255.0 blue:92/255.0 alpha:1];

    switchMoveFromTo.offTintColor = [UIColor colorWithRed:37/255.0 green:81/255.0 blue:92/255.0 alpha:1];

    switchMoveFromTo.textColor = [UIColor blackColor];

    switchMoveFromTo.onText = @”Moving To”;

    switchMoveFromTo.offText = @”Moving From”;

    //switch2.textFont = @””;

    [switchMoveFromTo setOnTextFontSize:7];

    [switchMoveFromTo setOffTextFontSize:7];

    [switchMoveFromTo addTarget:self action:@selector(switchStateChanged:) forControlEvents:UIControlEventValueChanged];

    [self.viewForSwitch addSubview:switchMoveFromTo];

    

    // Do any additional setup after loading the view.

}

– (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    

    //sample data

    

    // Dispose of any resources that can be recreated.

}

– (void)loadModels

{

    

    NSDictionary *dictionary = @{

                                 @”moveTo”: @”11111″,

                                 @”moveFrom”:@”22222″

                                 };

    

//    [[MCNetworkManager sharedNetworkManager] getVendorsList:dictionary withCompletionBlock:^(NSDictionary *response, NSError *error) {

//        NSLog(@”Response”);

//        NSArray *moveFromArray = response[@”result”][@”move_from”][@”tasks”];

//        NSArray *moveToArray = response[@”result”][@”move_to”][@”tasks”];

//        self.fromModelArray = [NSMutableArray array];

//        self.toModelArray = [NSMutableArray array];

//        [self generateVendorsModelsForArray:moveFromArray moveIntoArray:self.fromModelArray];

//        [self generateVendorsModelsForArray:moveToArray moveIntoArray:self.toModelArray];

//        self.modelArray = (self.vendorType == MCVendorTypeFrom) ? self.fromModelArray : self.toModelArray;

//        [self.taskVendorsTableView reloadData];

//        [self.activityIndicator stopAnimating];

//        self.activityIndicator.hidden = YES;

//    }];

    

    

    

    self.arrayJson = [Utility parseStatesResponseFileName:@”Json_File” FileType:@”json”];

    NSLog(@”%@”,self.arrayJson);

    

    NSDictionary *response = (NSDictionary *)self.arrayJson;

    

    NSArray *moveFromArray = response[@”result”][@”move_from”][@”tasks”];

            NSArray *moveToArray = response[@”result”][@”move_to”][@”tasks”];

            self.fromModelArray = [NSMutableArray array];

            self.toModelArray = [NSMutableArray array];

            [self generateVendorsModelsForArray:moveFromArray moveIntoArray:self.fromModelArray];

            [self generateVendorsModelsForArray:moveToArray moveIntoArray:self.toModelArray];

            self.modelArray = (self.vendorType == MCVendorTypeFrom) ? self.fromModelArray : self.toModelArray;

            [self.taskVendorsTableView reloadData];

            [self.activityIndicator stopAnimating];

            self.activityIndicator.hidden = YES;

}

     

     

– (void)generateVendorsModelsForArray:(NSArray *)array moveIntoArray:(NSMutableArray *)movingArray

{

         for(NSDictionary *taskWithVedorsList in array)

         {

             MCCallVendorTaskModel *model = [[MCCallVendorTaskModel alloc] init];

             //set task and vendors list details

             [model setDataFromDictionary:taskWithVedorsList];

             model.expanded = NO;

             [movingArray addObject:model];

         }

}

– (IBAction)switchStateChanged:(id)sender

{

    UISwitch *toFromswitch = (UISwitch *)sender;

    self.vendorType  = (toFromswitch.isOn) ? MCVendorTypeFrom : MCVendorTypeTo;

    [self filterTasks:self.searchTextField.text];

}

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    MCCallVendorTaskModel *taskModel = self.modelArray[section];

    NSInteger rows = (taskModel.expanded) ? ((taskModel.vendorsArray.count > 5) ? 6 : taskModel.vendorsArray.count) : 0;

    return rows;

}

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    NSString *identifier = vendorCell;

    MCCallVendorTaskModel *model = self.modelArray[indexPath.section];

    NSArray *vendorsArray = model.vendorsArray;

    if(indexPath.row > 4 && vendorsArray.count > 5)

    {

        identifier = viewMore;

    }

    MCCallVendorVendorCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    cell.delegate = self;

    cell.section = indexPath.section;

    cell.model = vendorsArray[indexPath.row];

    

    if([identifier isEqualToString:vendorCell])

    {

        //check if last cell and vendor cell

        if((indexPath.row == vendorsArray.count1))

        {

            dispatch_async(dispatch_get_main_queue(), ^{

                UIBezierPath *maskPath;

                maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds

                                                 byRoundingCorners:(UIRectCornerBottomRight|UIRectCornerBottomLeft)

                                                       cornerRadii:CGSizeMake(5.0, 5.0)];

                

                CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

                maskLayer.path = maskPath.CGPath;

                maskLayer.frame = cell.bounds;

                cell.layer.mask = maskLayer;

                cell.separator.hidden = YES;

            });

        }

        else

        {

            dispatch_async(dispatch_get_main_queue(), ^{

                UIBezierPath *maskPath;

                maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds

                                                 byRoundingCorners:(UIRectCornerBottomRight|UIRectCornerBottomLeft)

                                                       cornerRadii:CGSizeMake(0.0, 0.0)];

                

                CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

                maskLayer.path = maskPath.CGPath;

                maskLayer.frame = cell.bounds;

                cell.layer.mask = maskLayer;

                if((indexPath.row > 3 && vendorsArray.count > 5))

                {

                    cell.separator.hidden = YES;

                }

                else

                {

                    cell.separator.hidden = NO;

                }

            });

        }

       

    }

    else if ([identifier isEqualToString:viewMore])

    {

        dispatch_async(dispatch_get_main_queue(), ^{

            UIBezierPath *maskPath;

            maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds

                                             byRoundingCorners:(UIRectCornerBottomRight|UIRectCornerBottomLeft)

                                                   cornerRadii:CGSizeMake(5.0, 5.0)];

            

            CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

            maskLayer.path = maskPath.CGPath;

            maskLayer.frame = cell.bounds;

            cell.layer.mask = maskLayer;

        });

    }

    

    return cell;

}

– (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

{

    return self.modelArray.count;

}

– (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

{

    MCCallVendorTaskCell *cell = [tableView dequeueReusableCellWithIdentifier:taskSectionCell];

    cell.delegate = self;

    cell.model = self.modelArray[section];

    dispatch_async(dispatch_get_main_queue(), ^{

        UIBezierPath *maskPath;

        maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds

                                         byRoundingCorners:(UIRectCornerTopRight|UIRectCornerTopLeft)

                                               cornerRadii:CGSizeMake(5.0, 5.0)];

        

        CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

        maskLayer.path = maskPath.CGPath;

        maskLayer.frame = cell.bounds;

        cell.layer.mask = maskLayer;

    });

    return cell;

}

– (CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section

{

    return 20.0;

}

– (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section

{

    return 30.0;

}

-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section

{

    UIView *view = [[UIView alloc] initWithFrame:CGRectZero];

    view.backgroundColor = [UIColor clearColor];

    return  view;

}

#pragma mark – Task cell delegates –

– (void)expandCell:(MCCallVendorTaskCell *)cell

{

    for(int i=0; i< self.modelArray.count ; i++)

    {

        MCCallVendorTaskModel *model = self.modelArray[i];

        if(model != cell.model)

        {

            model.expanded = NO;

        }

    }

    cell.model.expanded = !(cell.model.expanded);

    [self.taskVendorsTableView reloadData];

}

#pragma  mark – Vendor cell delegates –

– (void)tappedViewMore:(MCCallVendorVendorCell *)cell

{

    //push a new controller

    MCVendorsListController *vendorsListController = [[UIStoryboard storyboardWithName:vendorsListControllerName bundle:nil] instantiateInitialViewController];

    //pass the selected vendors list,this a a parcular vendor cell, but we need to get list of the vendors for that section

    vendorsListController.model = self.modelArray[cell.section];

    [self.navigationController pushViewController:vendorsListController animated:YES];

}

– (void)tappedCallVendor:(MCCallVendorVendorCell *)cell

{

    //call the vendor

    [Utility makeCall:cell.model.vendorPhone];

}

– (IBAction)searchTasks:(id)sender

{

    NSString *textToSearch = ((UITextField *)sender).text ;

    [self filterTasks:textToSearch];

}

– (BOOL)textFieldShouldReturn:(UITextField *)textField

{

    [self.view endEditing:YES];

    return YES;

}

– (void)filterTasks:(NSString *)filterText

{

    NSLog(@”%@”,filterText);

    if(filterText.length)

    {

        NSArray *taskVendorArray = (self.vendorType == MCVendorTypeFrom) ? self.fromModelArray : self.toModelArray;

        NSString* filter =  filterTaskConstant;

        NSPredicate* predicate = [NSPredicate predicateWithFormat:filter, @”taskName”,filterText];

        NSArray* filteredData = [taskVendorArray filteredArrayUsingPredicate:predicate];

        //filtered Data

        self.modelArray = filteredData;

        NSLog(@”Filtered Data”);

        [self.taskVendorsTableView reloadData];

    }

    else

    {

        self.modelArray = (self.vendorType == MCVendorTypeFrom) ? self.fromModelArray : self.toModelArray;

        [self.taskVendorsTableView reloadData];

    }

}

– (IBAction)tapGesture:(id)sender

{

    [self.view endEditing:YES];

}

MCCallVendorTaskCell.h

#import <UIKit/UIKit.h>

#import “MCCallVendorTaskModel.h”

@class MCCallVendorTaskCell;

@protocol MCCallVendorTaskCellProtocol <NSObject>

– (void)expandCell:(MCCallVendorTaskCell *)cell;

@end

@interface MCCallVendorTaskCell : UITableViewCell

@property (nonatomic, strong) MCCallVendorTaskModel *model;

@property (nonatomic, assign) id <MCCallVendorTaskCellProtocol> delegate;

@end

MCCallVendorTaskCell.m

#import “MCCallVendorTaskCell.h”

@interface MCCallVendorTaskCell()

@property (weak, nonatomic) IBOutlet UILabel *taskName;

@property (weak, nonatomic) IBOutlet UIButton *expandButton;

@end

@implementation MCCallVendorTaskCell

– (IBAction)expandButtonAction:(id)sender

{

    if(self.delegate && [self.delegate respondsToSelector:@selector(expandCell:)])

    {

        [self.delegate expandCell:self];

        [self updateButtonState];

    }

}

– (void)setModel:(MCCallVendorTaskModel *)model

{

    _model = model;

    self.taskName.text = _model.taskName;

    [self updateButtonState];

}

– (void)updateButtonState

{

    if(self.model.expanded)

    {

        [self.expandButton setBackgroundImage:[UIImage imageNamed:@”drop-up”] forState:UIControlStateNormal];

    }

    else

    {

        [self.expandButton setBackgroundImage:[UIImage imageNamed:@”drop-down”] forState:UIControlStateNormal];

    }

}

@end

MCCallVendorTaskModel.h

#import <Foundation/Foundation.h>

#import “MCCallVendorVendorModel.h”

@interface MCCallVendorTaskModel : NSObject

@property (nonatomic, assign) BOOL expanded;

@property (nonatomic, strong) NSString *taskName;

@property (nonatomic, strong) NSMutableArray *vendorsArray; // of type vendors model

– (void)setDataFromDictionary:(NSDictionary *)dictionary;

@end

MCCallVendorTaskModel.m

#import “MCCallVendorTaskModel.h”

@implementation MCCallVendorTaskModel

– (void)setDataFromDictionary:(NSDictionary *)dictionary

{

    self.taskName = dictionary[@”name”];

    //vendors

    self.vendorsArray = [NSMutableArray array];

    NSArray *vendorsArray = dictionary[@”vendors”];

    for(NSDictionary *vendorDictionay in vendorsArray )

    {

        MCCallVendorVendorModel *vendorModel = [[MCCallVendorVendorModel alloc] init];

        [vendorModel setDataFromDictionary:vendorDictionay];

        [self.vendorsArray addObject:vendorModel];

    }

}

@end

MCCallVendorVendorCell.h

#import <UIKit/UIKit.h>

#import “MCCallVendorVendorModel.h”

@class MCCallVendorVendorCell;

@protocol MCCallVendorVendorCellProtocol <NSObject>

– (void)tappedCallVendor:(MCCallVendorVendorCell *)cell;

@optional

– (void)tappedViewMore:(MCCallVendorVendorCell *)cell;

@end

@interface MCCallVendorVendorCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UIView *separator;

@property (nonatomic, weak) id <MCCallVendorVendorCellProtocol> delegate;

@property (nonatomic, strong) MCCallVendorVendorModel *model;

@property (nonatomic, assign) NSUInteger section;

@end

MCCallVendorVendorCell.m

#import “MCCallVendorVendorCell.h”

@interface MCCallVendorVendorCell ()

@property (weak, nonatomic) IBOutlet UILabel *vendorName;

@end

@implementation MCCallVendorVendorCell

– (void)setModel:(MCCallVendorVendorModel *)model

{

    _model = model;

    self.vendorName.text = _model.vendorName;

}

– (IBAction)callVendorAction:(id)sender

{

    if(self.delegate && [self.delegate respondsToSelector:@selector(tappedCallVendor:)])

    {

        [self.delegate tappedCallVendor:self];

    }

}

– (IBAction)viewMoreAction:(id)sender

{

    if(self.delegate && [self.delegate respondsToSelector:@selector(tappedViewMore:)])

    {

        [self.delegate tappedViewMore:self];

    }

}

@end

MCCallVendorVendorModel.h

#import <Foundation/Foundation.h>

@interface MCCallVendorVendorModel : NSObject

@property (nonatomic, strong) NSString *vendorName;

@property (nonatomic, strong) NSString *vendorPhone;

– (void)setDataFromDictionary:(NSDictionary *)dictionary;

@end

MCCallVendorVendorModel.m

#import “MCCallVendorVendorModel.h”

@implementation MCCallVendorVendorModel

– (void)setDataFromDictionary:(NSDictionary *)dictionary

{

    self.vendorName = dictionary[@”name”];

    self.vendorPhone = dictionary[@”phone”];

}

@end

MCVendorsListController.h

#import <UIKit/UIKit.h>

#import “MCCallVendorTaskModel.h”

@interface MCVendorsListController : UIViewController

@property (nonatomic, strong) MCCallVendorTaskModel *model; // task model with name and list of vendors

@end

MCVendorsListController.m

#import “MCVendorsListController.h”

#import “MCCallVendorVendorCell.h”

#import “Utility.h”

NSString *const vendorsFilterString =  @”%K CONTAINS[c] %@”;

NSString *const vendorCellIdentifier = @”vendorCell”;

@interface MCVendorsListController()<UITableViewDataSource, UITableViewDelegate , MCCallVendorVendorCellProtocol>

@property (weak, nonatomic) IBOutlet UITableView *vendorsTableView;

@property (nonatomic, strong) NSArray *modelsArray;

@end

@implementation MCVendorsListController

– (void)viewDidLoad

{

    [super viewDidLoad];

    self.navigationController.navigationBarHidden = YES;

    [self loadAllVendors];

}

– (void)loadAllVendors

{

    self.modelsArray = self.model.vendorsArray;

    [self.vendorsTableView reloadData];

}

– (IBAction)backButtonAction:(id)sender

{

    [self.navigationController popViewControllerAnimated:YES];

}

– (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

{

    return 1;

}

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    return self.modelsArray.count;

}

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    MCCallVendorVendorCell *cell = [tableView dequeueReusableCellWithIdentifier:vendorCellIdentifier];

    cell.model = self.modelsArray[indexPath.row];

    cell.delegate = self;

    return cell;

}

– (IBAction)searchVendors:(id)sender

{

    NSString *textToSearch = ((UITextField *)sender).text ;

    NSLog(@”%@”,textToSearch);

    if(textToSearch.length)

    {

        NSArray *taskVendorArray = self.model.vendorsArray;

        NSString* filter = vendorsFilterString;

        NSPredicate* predicate = [NSPredicate predicateWithFormat:filter, @”vendorName”,textToSearch];

        NSArray* filteredData = [taskVendorArray filteredArrayUsingPredicate:predicate];

        //filtered Data

        self.modelsArray = filteredData;

        NSLog(@”Filtered Data”);

        [self.vendorsTableView reloadData];

    }

    else

    {

        self.modelsArray = self.model.vendorsArray;

        [self.vendorsTableView reloadData];

    }

}

#pragma mark – vendor cell delegates –

– (void)tappedCallVendor:(MCCallVendorVendorCell *)cell

{

    [Utility makeCall:cell.model.vendorPhone];

}

@end

Click here to download Custom Tableview, Click on table cell and Expand with another TableView, TableView Search Project

Leave a comment