Skip to content

Commit

Permalink
Merge pull request #416 from chriscox/table-accessoryView
Browse files Browse the repository at this point in the history
Add support for attaching custom accessoryViews to table model objects.
  • Loading branch information
liquidx committed Jul 11, 2013
2 parents 19dd716 + b0c25c9 commit f35c234
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/core/src/NIActions+Subclassing.h
Expand Up @@ -34,5 +34,6 @@
@property (nonatomic, NI_WEAK) id target;

- (NIObjectActions *)actionForObjectOrClassOfObject:(id<NSObject>)object;
- (UIView *)accessoryViewForObject:(id<NSObject>)object;

@end
82 changes: 82 additions & 0 deletions src/core/src/NIActions.h
Expand Up @@ -71,6 +71,28 @@ NSArray *objects = @[
NSLog(@"Object was tapped: %@", object);
}];
@endcode
*
* <h3>Setting a Custom Accessory View</h3>
* For either tap block or selector invocations, there is an option to set a custom accessoryView.
*
* The following is an example of setting an accessoryView:
*
@code
UISwitch *switchControl = [[UISwitch alloc] init];
switchControl.tag = 1;
[switchControl addTarget:self action:@selector(switched:) forControlEvents:UIControlEventValueChanged];
NSArray *objects = @[
[NITitleCellObject objectWithTitle:@"Custom Accessory View"],
[self.actions attachToObject:[NITitleCellObject objectWithTitle:@"UISwitch Cell"]
accessoryView:switchControl
tapSelector:nil]
];
- (void)switched:(id)switchControl {
NSLog(@"Switch %i is now %@.", switchControl.tag, (switchControl.on) ? @"on" : @"off");
}
@endcode
*
*/
@interface NIActions : NSObject
Expand All @@ -83,10 +105,12 @@ NSArray *objects = @[
- (id)attachToObject:(id<NSObject>)object tapBlock:(NIActionBlock)action;
- (id)attachToObject:(id<NSObject>)object detailBlock:(NIActionBlock)action;
- (id)attachToObject:(id<NSObject>)object navigationBlock:(NIActionBlock)action;
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapBlock:(NIActionBlock)action;

- (id)attachToObject:(id<NSObject>)object tapSelector:(SEL)selector;
- (id)attachToObject:(id<NSObject>)object detailSelector:(SEL)selector;
- (id)attachToObject:(id<NSObject>)object navigationSelector:(SEL)selector;
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapSelector:(SEL)selector;

#pragma mark Mapping Classes

Expand All @@ -101,6 +125,7 @@ NSArray *objects = @[
#pragma mark Object State

- (BOOL)isObjectActionable:(id<NSObject>)object;
- (BOOL)objectHasAccessoryView:(id<NSObject>)object;

+ (id)objectFromKeyClass:(Class)keyClass map:(NSMutableDictionary *)map;

Expand Down Expand Up @@ -213,6 +238,31 @@ NIActionBlock NIPushControllerAction(Class controllerClass);
* @fn NIActions::attachToObject:navigationBlock:
*/

/**
* Attaches a tap action with an accessory view to the given object.
*
* A cell with an attached tap action will have its selectionStyle set to
* @c tableViewCellSelectionStyle when the cell is displayed.
*
* The action will be executed when the object's corresponding cell is tapped. The object argument
* of the block will be the object to which this action was attached. The target argument of the
* block will be this receiver's @c target.
*
* Return NO if the tap action is used to present a modal view controller. This provides a visual
* reminder to the user when the modal controller is dismissed as to which cell was tapped to invoke
* the modal controller.
*
* The tap action will be invoked first, followed by the navigation action if one is attached.
*
* @param object The object to attach the action to. This object must be contained within
* an NITableViewModel.
* @param accessoryView The custom accessoryView to be added. If set, ignore cell accessoryType.
* @param action The tap action block.
* @returns The object that you attached this action to.
* @fn NIActions::attachToObject:accessoryView:tapBlock:
* @sa NIActions::attachToObject:accessoryView:tapSelector:
*/

/**
* Attaches a tap selector to the given object.
*
Expand Down Expand Up @@ -294,6 +344,38 @@ NIActionBlock NIPushControllerAction(Class controllerClass);
* @sa NIActions::attachToObject:navigationBlock:
*/

/**
* Attaches a tap selector with an accessory view to the given object.
*
* The method signature for the selector is:
@code
- (BOOL)didTapObject:(id)object;
@endcode
*
* A cell with an attached tap action will have its selectionStyle set to
* @c tableViewCellSelectionStyle when the cell is displayed.
*
* The selector will be performed on the action object's target when a cell with a tap selector is
* tapped, unless that selector does not exist on the @c target in which case nothing happens.
*
* If the selector invocation returns YES then the cell will be deselected immediately after the
* invocation completes its execution. If NO is returned then the cell's selection will remain.
*
* Return NO if the tap action is used to present a modal view controller. This provides a visual
* reminder to the user when the modal controller is dismissed as to which cell was tapped to invoke
* the modal controller.
*
* The tap action will be invoked first, followed by the navigation action if one is attached.
*
* @param object The object to attach the selector to. This object must be contained within
* an NITableViewModel.
* @param accessoryView The custom accessoryView to be added. If set, ignore cell accessoryType.
* @param selector The selector that will be invoked by this action.
* @returns The object that you attached this action to.
* @fn NIActions::attachToObject:accessoryView:tapSelector:
* @sa NIActions::attachToObject:accessoryView:tapBlock:
*/

/** @name Mapping Classes */

/**
Expand Down
63 changes: 56 additions & 7 deletions src/core/src/NIActions.m
Expand Up @@ -25,7 +25,9 @@ @interface NIActions()

@property (nonatomic, NI_STRONG) NSMutableDictionary* objectMap;
@property (nonatomic, NI_STRONG) NSMutableSet* objectSet;
@property (nonatomic, NI_STRONG) NSMutableDictionary* classMap;
@property (nonatomic, NI_STRONG) NSMutableDictionary* objectClassMap;
@property (nonatomic, NI_STRONG) NSMutableDictionary* accessoryMap;
@property (nonatomic, NI_STRONG) NSMutableSet* accessorySet;

@end

Expand All @@ -37,7 +39,9 @@ @implementation NIActions

@synthesize objectMap = _objectMap;
@synthesize objectSet = _objectSet;
@synthesize classMap = _classMap;
@synthesize objectClassMap = _objectClassMap;
@synthesize accessoryMap = _accessoryMap;
@synthesize accessorySet = _accessorySet;


///////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -46,7 +50,9 @@ - (id)initWithTarget:(id)target {
_target = target;
_objectMap = [[NSMutableDictionary alloc] init];
_objectSet = [[NSMutableSet alloc] init];
_classMap = [[NSMutableDictionary alloc] init];
_objectClassMap = [[NSMutableDictionary alloc] init];
_accessoryMap = [[NSMutableDictionary alloc] init];
_accessorySet = [[NSMutableSet alloc] init];
}
return self;
}
Expand Down Expand Up @@ -76,6 +82,9 @@ - (id)keyForObject:(id<NSObject>)object {
// actionForObjectOrClassOfObject: determines whether an action has been attached to an object
// or class of object and then returns the NIObjectActions or nil if no actions have been attached.
//
// accessoryViewForObject: determines whether an accessoryView has been attached to an object
// and then returns the UIView or nil if no accessoryView has been attached.
//


///////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -96,10 +105,10 @@ - (NIObjectActions *)actionForObject:(id<NSObject>)object {
// Retrieves an NIObjectActions object for the given class or creates one if it doesn't yet exist
// so that actions may be attached.
- (NIObjectActions *)actionForClass:(Class)class {
NIObjectActions* action = [self.classMap objectForKey:class];
NIObjectActions* action = [self.objectClassMap objectForKey:class];
if (nil == action) {
action = [[NIObjectActions alloc] init];
[self.classMap setObject:action forKey:(id<NSCopying>)class];
[self.objectClassMap setObject:action forKey:(id<NSCopying>)class];
}
return action;
}
Expand All @@ -111,12 +120,20 @@ - (NIObjectActions *)actionForObjectOrClassOfObject:(id<NSObject>)object {
id key = [self keyForObject:object];
NIObjectActions* action = [self.objectMap objectForKey:key];
if (nil == action) {
action = [self.class objectFromKeyClass:object.class map:self.classMap];
action = [self.class objectFromKeyClass:object.class map:self.objectClassMap];
}
return action;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
// Fetches any accessoryView for a given object.
- (UIView *)accessoryViewForObject:(id<NSObject>)object {
id key = [self keyForObject:object];
return [self.accessoryMap objectForKey:key];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Public Methods
Expand Down Expand Up @@ -146,6 +163,17 @@ - (id)attachToObject:(id<NSObject>)object navigationBlock:(NIActionBlock)action
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapBlock:(NIActionBlock)action {
[self attachToObject:object tapBlock:action];
if (accessoryView) {
[self.accessorySet addObject:object];
[self.accessoryMap setObject:accessoryView forKey:[self keyForObject:object]];
}
return object;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)attachToObject:(id<NSObject>)object tapSelector:(SEL)selector {
[self.objectSet addObject:object];
Expand All @@ -170,6 +198,17 @@ - (id)attachToObject:(id<NSObject>)object navigationSelector:(SEL)selector {
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapSelector:(SEL)selector {
[self attachToObject:object tapSelector:selector];
if (accessoryView) {
[self.accessorySet addObject:object];
[self.accessoryMap setObject:accessoryView forKey:[self keyForObject:object]];
}
return object;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)attachToClass:(Class)aClass tapBlock:(NIActionBlock)action {
[self actionForClass:aClass].tapAction = action;
Expand Down Expand Up @@ -214,12 +253,22 @@ - (BOOL)isObjectActionable:(id<NSObject>)object {

BOOL objectIsActionable = [self.objectSet containsObject:object];
if (!objectIsActionable) {
objectIsActionable = (nil != [self.class objectFromKeyClass:object.class map:self.classMap]);
objectIsActionable = (nil != [self.class objectFromKeyClass:object.class map:self.objectClassMap]);
}
return objectIsActionable;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)objectHasAccessoryView:(id<NSObject>)object {
if (nil == object) {
return NO;
}

return [self.accessorySet containsObject:object];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
+ (id)objectFromKeyClass:(Class)keyClass map:(NSMutableDictionary *)map {
id object = [map objectForKey:keyClass];
Expand Down
8 changes: 7 additions & 1 deletion src/models/src/NITableViewActions.m
Expand Up @@ -172,9 +172,15 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)ce
NITableViewModel* model = (NITableViewModel *)tableView.dataSource;
id object = [model objectAtIndexPath:indexPath];
if ([self isObjectActionable:object]) {
cell.accessoryType = [self accessoryTypeForObject:object];
if ([self objectHasAccessoryView:object]) {
cell.accessoryView = [self accessoryViewForObject:object];
} else {
cell.accessoryView = nil;
cell.accessoryType = [self accessoryTypeForObject:object];
}
cell.selectionStyle = [self selectionStyleForObject:object];
} else {
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Expand Down

0 comments on commit f35c234

Please sign in to comment.