iOS开发之功能模块--用runtime给UIView类别拓展PressMenu工具
这是个很有用的列别工具类,在聊天对话框添加和QQ一样的"复制、粘贴、取消"等选项,而且使用起来很方便,只要找到聊天泡泡内部的某个View,比如Label或者背景冒泡的UIImageView,直接add...即可实现下面的效果:
直接上源码:
UIView+PressMenu.h
1 #import <UIKit/UIKit.h> 2 3 @interface UIView (PressMenu) 4 @property (strong, nonatomic) NSArray *menuTitles; 5 @property (strong, nonatomic) UILongPressGestureRecognizer *pressGR; 6 @property (copy, nonatomic) void(^menuClickedBlock)(NSInteger index, NSString *title); 7 @property (strong, nonatomic) UIMenuController *menuVC; 8 9 - (void)addPressMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block; 10 - (void)showMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block; 11 12 - (BOOL)isMenuVCVisible; 13 - (void)removePressMenu; 14 @end
UIView+PressMenu.m
1 #import "UIView+PressMenu.h" 2 #import <objc/runtime.h> 3 4 @implementation UIView (PressMenu) 5 6 static const NSString *kPressMenuSelectorPrefix = @"easePressMenuClicked_"; 7 static char PressMenuTitlesKey, PressMenuBlockKey, PressMenuGestureKey, MenuVCKey; 8 9 #pragma mark M 10 - (void)addPressMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block{ 11 self.userInteractionEnabled = YES; 12 self.menuClickedBlock = block; 13 self.menuTitles = menuTitles; 14 if (self.pressGR == nil) { 15 self.pressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePress:)]; 16 } 17 [self addGestureRecognizer:self.pressGR]; 18 } 19 20 - (void)showMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block{ 21 self.menuClickedBlock = block; 22 self.menuTitles = menuTitles; 23 [self p_showMenu]; 24 } 25 26 - (BOOL)isMenuVCVisible{ 27 if (self.menuVC) { 28 return [self.menuVC isMenuVisible]; 29 } 30 return NO; 31 } 32 33 - (void)removePressMenu{ 34 if (self.menuVC) { 35 [self.menuVC setMenuVisible:NO animated:YES]; 36 self.menuVC = nil; 37 } 38 if ([self.pressGR isKindOfClass:[UILongPressGestureRecognizer class]]) { 39 [self removeGestureRecognizer:self.pressGR]; 40 self.pressGR = nil; 41 } 42 if (self.menuClickedBlock) { 43 self.menuClickedBlock = nil; 44 } 45 if (self.menuTitles) { 46 self.menuTitles = nil; 47 } 48 } 49 50 #pragma mark SET_GET 51 - (void)setMenuTitles:(NSArray *)menuTitles{ 52 objc_setAssociatedObject(self, &PressMenuTitlesKey, menuTitles, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 53 } 54 - (NSArray *)menuTitles{ 55 return objc_getAssociatedObject(self, &PressMenuTitlesKey); 56 } 57 58 - (void)setMenuClickedBlock:(void (^)(NSInteger, NSString *))menuClickedBlock{ 59 objc_setAssociatedObject(self, &PressMenuBlockKey, menuClickedBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); 60 } 61 - (void (^)(NSInteger, NSString *))menuClickedBlock{ 62 return objc_getAssociatedObject(self, &PressMenuBlockKey); 63 } 64 65 - (void)setPressGR:(UILongPressGestureRecognizer *)pressGR{ 66 objc_setAssociatedObject(self, &PressMenuGestureKey, pressGR, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 67 } 68 - (UILongPressGestureRecognizer *)pressGR{ 69 return objc_getAssociatedObject(self, &PressMenuGestureKey); 70 } 71 72 - (void)setMenuVC:(UIMenuController *)menuVC{ 73 objc_setAssociatedObject(self, &MenuVCKey, menuVC, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 74 } 75 - (UIMenuController *)menuVC{ 76 return objc_getAssociatedObject(self, &MenuVCKey); 77 } 78 79 #pragma mark canPerformAction 80 - (BOOL)canBecomeFirstResponder{ 81 if (self.menuClickedBlock) { 82 return YES; 83 }else{ 84 return [super canBecomeFirstResponder]; 85 } 86 } 87 88 -(BOOL)canPerformAction:(SEL)action withSender:(id)sender{ 89 if (self.menuClickedBlock) { 90 for (int i=0; i<self.menuTitles.count; i++) { 91 if (action == NSSelectorFromString([NSString stringWithFormat:@"%@%d:", kPressMenuSelectorPrefix, i])) { 92 return YES; 93 } 94 } 95 return NO; 96 }else{ 97 return [super canPerformAction:action withSender:sender]; 98 } 99 } 100 101 -(void)handlePress:(UIGestureRecognizer*)recognizer{ 102 if (recognizer.state == UIGestureRecognizerStateBegan) { 103 [self p_showMenu]; 104 } 105 } 106 107 - (void)p_showMenu{ 108 [self becomeFirstResponder]; 109 NSMutableArray *menuItems = [[NSMutableArray alloc] initWithCapacity:self.menuTitles.count]; 110 Class cls = [self class]; 111 SEL imp = @selector(pressMenuClicked:); 112 for (int i=0; i<self.menuTitles.count; i++) { 113 NSString *title = [self.menuTitles objectAtIndex:i]; 114 //注册名添加方法sel,sel的具体实现在imp(pressMenuClicked:) 115 SEL sel = sel_registerName([[NSString stringWithFormat:@"%@%d:", kPressMenuSelectorPrefix, i] UTF8String]); 116 class_addMethod(cls, sel, [cls instanceMethodForSelector:imp], "v@"); 117 UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:title action:sel]; 118 [menuItems addObject:menuItem]; 119 } 120 UIMenuController *menu = [UIMenuController sharedMenuController]; 121 [menu setMenuItems:menuItems]; 122 [menu setTargetRect:self.frame inView:self.superview]; 123 [menu setMenuVisible:YES animated:YES]; 124 self.menuVC = menu; 125 } 126 127 - (void)pressMenuClicked:(id)sender { 128 NSString *selStr = NSStringFromSelector(_cmd); 129 NSString *indexStr = [selStr substringFromIndex:kPressMenuSelectorPrefix.length]; 130 NSInteger index = indexStr.integerValue; 131 if (index >=0 && index<self.menuTitles.count) { 132 NSString *title = [self.menuTitles objectAtIndex:index]; 133 if (self.menuClickedBlock) { 134 self.menuClickedBlock(index, title); 135 } 136 } 137 } 138 139 @end