Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table custom accessoryViews #416

Merged
merged 2 commits into from Jul 11, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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