Skip to content

Commit b728ff3

Browse files
Implemented jessesquires#810: An easier way to handle custom menu actions.
1 parent fa7e42b commit b728ff3

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

JSQMessagesDemo/DemoMessagesViewController.m

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ - (void)viewDidLoad
3636
{
3737
[super viewDidLoad];
3838

39+
[JSQMessagesCollectionViewCell registerMenuAction:@selector(delete:)];
40+
3941
self.title = @"JSQMessages";
4042

4143
/**
@@ -502,7 +504,25 @@ - (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collection
502504
return cell;
503505
}
504506

507+
#pragma mark - UICollectionView Delegate
505508

509+
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
510+
{
511+
if (action == @selector(delete:)) {
512+
return YES;
513+
}
514+
515+
return [super collectionView:collectionView canPerformAction:action forItemAtIndexPath:indexPath withSender:sender];
516+
}
517+
518+
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
519+
{
520+
if (action == @selector(delete:)) {
521+
NSLog(@"delegate action %@", NSStringFromSelector(action));
522+
} else {
523+
[super collectionView:collectionView performAction:action forItemAtIndexPath:indexPath withSender:sender];
524+
}
525+
}
506526

507527
#pragma mark - JSQMessages collection view flow layout delegate
508528

JSQMessagesViewController/Views/JSQMessagesCollectionView.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,17 @@ - (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)ce
165165
touchLocation:position];
166166
}
167167

168+
- (void)messagesCollectionViewCell:(JSQMessagesCollectionViewCell *)cell didPerformAction:(SEL)action withSender:(id)sender
169+
{
170+
NSIndexPath *indexPath = [self indexPathForCell:cell];
171+
if (indexPath == nil) {
172+
return;
173+
}
174+
175+
[self.delegate collectionView:self
176+
performAction:action
177+
forItemAtIndexPath:indexPath
178+
withSender:sender];
179+
}
180+
168181
@end

JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@
6060
*/
6161
- (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)cell atPosition:(CGPoint)position;
6262

63+
/**
64+
* Tells the delegate that an actions has been selected from the menu of this cell.
65+
*
66+
* @param cell The cell that displayed the menu.
67+
* @param action The action that has been performed.
68+
* @param sender The object that initiated the action.
69+
*
70+
* @discussion This method is automatically called for any registered actions.
71+
*
72+
* @see `JSQMessagesCollectionViewCell`
73+
*/
74+
- (void)messagesCollectionViewCell:(JSQMessagesCollectionViewCell *)cell didPerformAction:(SEL)action withSender:(id)sender;
75+
6376
@end
6477

6578

@@ -180,4 +193,12 @@
180193
*/
181194
+ (NSString *)mediaCellReuseIdentifier;
182195

196+
/**
197+
* Registeres an action to be available in the cell's menu.
198+
*
199+
* @discussion Non-Standard actions still need to be added to the `UIMenuController`
200+
* manually.
201+
*/
202+
+ (void)registerMenuAction:(SEL)action;
203+
183204
@end

JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.m

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,21 @@ - (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFl
6666
@end
6767

6868

69+
static NSMutableArray *jsqMessagesCollectionViewCellActions = nil;
70+
6971

7072
@implementation JSQMessagesCollectionViewCell
7173

7274
#pragma mark - Class methods
7375

76+
+ (void)initialize
77+
{
78+
static dispatch_once_t onceToken;
79+
dispatch_once(&onceToken, ^{
80+
jsqMessagesCollectionViewCellActions = [[NSMutableArray alloc] init];
81+
});
82+
}
83+
7484
+ (UINib *)nib
7585
{
7686
return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle bundleForClass:[self class]]];
@@ -86,6 +96,11 @@ + (NSString *)mediaCellReuseIdentifier
8696
return [NSString stringWithFormat:@"%@_JSQMedia", NSStringFromClass([self class])];
8797
}
8898

99+
+ (void)registerMenuAction:(SEL)action
100+
{
101+
[jsqMessagesCollectionViewCellActions addObject:NSStringFromSelector(action)];
102+
}
103+
89104
#pragma mark - Initialization
90105

91106
- (void)awakeFromNib
@@ -216,6 +231,37 @@ - (void)setBounds:(CGRect)bounds
216231
}
217232
}
218233

234+
#pragma mark - Menu actions
235+
236+
- (BOOL)respondsToSelector:(SEL)aSelector
237+
{
238+
if ([jsqMessagesCollectionViewCellActions containsObject:NSStringFromSelector(aSelector)]) {
239+
return YES;
240+
} else {
241+
return [super respondsToSelector:aSelector];
242+
}
243+
}
244+
245+
- (void)forwardInvocation:(NSInvocation *)anInvocation
246+
{
247+
if ([jsqMessagesCollectionViewCellActions containsObject:NSStringFromSelector(anInvocation.selector)]) {
248+
id sender;
249+
[anInvocation getArgument:&sender atIndex:0];
250+
[self.delegate messagesCollectionViewCell:self didPerformAction:anInvocation.selector withSender:sender];
251+
} else {
252+
[super forwardInvocation:anInvocation];
253+
}
254+
}
255+
256+
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
257+
{
258+
if ([jsqMessagesCollectionViewCellActions containsObject:NSStringFromSelector(aSelector)]) {
259+
return [NSMethodSignature signatureWithObjCTypes: "v@:@"];
260+
} else {
261+
return [super methodSignatureForSelector:aSelector];
262+
}
263+
}
264+
219265
#pragma mark - Setters
220266

221267
- (void)setBackgroundColor:(UIColor *)backgroundColor

0 commit comments

Comments
 (0)