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

 

posted @ 2016-08-05 20:56  何杨  阅读(470)  评论(0编辑  收藏  举报