Question

I have 2 methods that add the Previous, Next & Done toolbar above the iOS Keyboard and handle these actions. I'm looking for a way to code these methods once and reuse it across multiple UITableViewControllers. (DRY Code)

I find myself copy and pasting these methods into each UITableViewController. If I make a small change, I have to copy and pastes that change everywhere. The code below is just an example, I seem to be repeating myself a lot in my code.

Here's an example of the code I'd like to reuse:

- (void) createInputAccessoryView
{
    _inputAccView = [[UIView alloc] initWithFrame:CGRectMake(10,0,310,42)];

    UIToolbar *keyboardToolbar = [[UIToolbar alloc] init];
    keyboardToolbar.barStyle = UIBarStyleBlackTranslucent;
    [keyboardToolbar sizeToFit];

    _segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Previous", @"Next", nil]];
    [_segmentedControl setSegmentedControlStyle:UISegmentedControlStyleBar];
    [_segmentedControl addTarget:self action:@selector(nextPrevious:) forControlEvents:UIControlEventValueChanged];

    UIBarButtonItem *nextPrevButton = [[UIBarButtonItem alloc] initWithCustomView:_segmentedControl];

    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];

    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(resignKeyboard)];

    NSArray *barItems = [NSArray arrayWithObjects:nextPrevButton, flexSpace, doneBtn, nil];
    [keyboardToolbar setItems:barItems];

    [_inputAccView addSubview:keyboardToolbar];

}

- (void) nextPrevious:(id) sender
{
    switch(_activeTxtField.tag) {
        case 1:
            //Recipe Name
            if (_segmentedControl.selectedSegmentIndex == 1){
                [_descriptionTextField becomeFirstResponder];
                _activeTxtField = _descriptionTextField;
            }
            break;
        case 2:
            //Recipe Description
            if (_segmentedControl.selectedSegmentIndex == 0){
                [_nameTextField becomeFirstResponder];
                _activeTxtField = _nameTextField;
            }
        default:
            break;
    }
}
Was it helpful?

Solution

Create a custom UIView that defines the common input accessory view. Should include a definition of a delegate to allow the class using the accessory view to handle, for example, previous/next button taps as appropriate. Here's a header file example for a keyboard accessory view:

#import <UIKit/UIKit.h>

@class KeyboardAccessoryView;

@protocol KeyboardAccessoryViewDelegate <NSObject>

-(void)accessoryNext:(id)sender;
-(void)accessoryPrevious:(id)sender;

@end

@interface InputAccessoryView : UIView

@property (nonatomic, weak) id<KeyboardAccessoryViewDelegate> delegate;
@property (nonatomic, setter = enablePrevious:) BOOL previousEnabled;
@property (nonatomic, setter = enableNext:) BOOL nextEnabled;

-(id)initPreviousNextAccessory;

@end

Edit - showing details of use in a UIViewController.

The .h file:

#import <UIKit/UIKit.h>
#import "KeyboardAccessoryView.h"

@interface MyViewController : UIViewController <KeyboardAccessoryViewDelegate>

//...

@end

The .m file:

#import "MyViewController.h"

@interface MyViewController () {
    KeyboardAccessoryView *inputAccessoryView;
}

@end

@implementation MyViewController

//...

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    inputAccessoryView = [[KeyboardAccessoryView alloc] initPreviousNextAccessory];
    inputAccessoryView.delegate = self;

    //...
}


-(void)accessoryNext:(id)sender{
    // handle Next
}

-(void)accessoryPrevious:(id)sender{
    // handle Previous
}

//...

@end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top