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], "[email protected]");
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
时间: 2024-12-26 03:23:22

iOS开发之功能模块--用runtime给UIView类别拓展PressMenu工具的相关文章

IOS开发之功能模块--给任意的UIView添加点击事件

前言:好久没写博客,今天来一波.我在实际项目开发中,会遇到这样功能需求:我已经搭好了iOS的UI界面,但是很多界面的子View用了UIView,然后这些UIView中用了UILabel和UIImageView,然后接着需求要这些View能够有点击事件,比如一点击就跳转到某个控制器.一开始懵逼了,难道我还要把他们全部改成UIButton,但是UIButton不好添加子View,难道我还要全部自定义一下UIButton,就算自定义好了,在项目已经打好的界面还是要一个个替换,多麻烦.所以就想到通过UI

iOS开发之功能模块--高仿Boss直聘的常用语的开发

首先上Boss直聘的功能界面截图,至于交互请读者现在Boss直聘去交互体验:     项目要高仿Boss直聘的IM常用语的交互功能,居然花费了我前后17个小时完成,这回自己测试了很多遍,代码质量很高,交互很流畅,仿真度也很高,重点综合性的用到了很多东西:runtime.代理传值.block传值.textView的系统通知监听.富文本.自定义封装.本地化增删改等等.其实这些都是基础,重点是功能的交互逻辑或者是业务逻辑的分析,然后正确实现,并经过尽可能多情况的自我测试通过,没有基础Bug,也没有任何

iOS开发之功能模块--Apns推送中的的json格式介绍

在开发向苹果Apns推送消息服务功能,我们需要根据Apns接受的数据格式进行推送.下面接受我在进行apns推送时候总结的一点apns服务接受的Json数据格式 示例 1: 以下负载包含哦一个简单的 aps 字典.它使用字符串而不是字典作为 alert 的值,该负载同样包含了一个自定义的属性数组. { "aps" : { "alert" : "message" },//alert表示推送的消息文本 "parm" : [ &quo

iOS开发之功能模块--推送之坑问题解决

苹果开发证书中,有一个根证书,根证书可以绑定相关的开发者设备合作开发一个app项目,如果是多人团队一般根证书是由老大搞定和统一管理我们的设备,这时候老大他会用到他电脑的keychain来生成P12文件,然后并把根证书一并给我们用. 但是,开发苹果推送功能的人不一定是老大,比如老大交给我来弄这个推送证书并给app添加推送功能,而生成苹果的推送cer后缀的证书,就当然在我的电脑生成了,当然肯定要通过老大用的那个开发者账号登录苹果官网,并且要下载和app同一个bundle ID一致的推送证书: 下载好

iOS开发之功能模块--高仿Boss直聘的IM界面交互功能

本人公司项目属于社交类,高仿Boss直聘早期的版本,现在Boss直聘界面风格,交互风格都不如Boss直聘以前版本的好看. 本人通过iPhone模拟器和本人真机对聊,将完成的交互功能通过Mac截屏模拟器来录制基本的交互功能. 界面因为动态截图工具本身不完美,截屏失真,所以存在有的部分UI颜色稍微变化了,比如白色稍微变灰暗色,不是项目本身的问题. 因为是本公司项目,不提供源码,只提供交互动态图仅供观赏??. (备注:Boss直聘分为个人端和企业端) 1.基本功能描述: 在个人端,一开始会话列表没有任

iOS开发之功能模块--关于自定义TabBar条

只上项目中用到的代码: 1.实现重写TabBar的TabBarItem,然后在中间额外加一个按钮. 1 #import <UIKit/UIKit.h> 2 3 @interface BikeTabBar : UITabBar 4 5 @end 1 #import "BikeTabBar.h" 2 3 @interface BikeTabBar () 4 5 //@property (nonatomic,weak)UIButton *centerButton; 6 7 @en

IOS开发之功能模块--输入框随着键盘的位置移动而移动

废话不多说,先直接上效果图: 先熟悉一下在Cocoa框架中会用到的key键: 然后直接上Demo的源码截图: 看代码之前,补充说一句,Demo中的文本框以及文本框的背后灰色的View是通过storyboard中的autoresizing布局的. 上面源码下载链接: http://pan.baidu.com/s/1jHXD7eQ 密码: uqww 在OC中,通过 transform 属性可以修改对象的平移.缩放比例和旋转角度. 那么就用transform做一个稍微的优化:

iOS开发之功能模块--模糊效果

1.先介绍一个好用的实现模糊效果的框架:https://github.com/YouXianMing/UIImageBlur 2.iOS8 中 UIVisualEffectView 模糊效果的使用 ,能够实时渲染,但是弊端就是iOS7以下不能用.

iOS开发:详解Objective-C runTime

Objective-C总Runtime的那点事儿(一)消息机制 最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎必问,例如:RunLoop,Block,内存管理等.其他的问题如果有机会我会在其他文章中介绍. 本篇文章主要介绍RunTime. RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编