这是个很有用的列别工具类,在聊天对话框添加和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=; 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=; 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 >= && 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

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

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

    前言:好久没写博客,今天来一波.我在实际项目开发中,会遇到这样功能需求:我已经搭好了iOS的UI界面,但是很多界面的子View用了UIView,然后这些UIView中用了UILabel和UIImage ...

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

    首先上Boss直聘的功能界面截图,至于交互请读者现在Boss直聘去交互体验:     本人的公司项目要高仿Boss直聘的IM常用语的交互功能,居然花费了我前后17个小时完成,这回自己测试了很多遍,代码 ...

  3. IOS开发之功能模块--自定义导航控制器类常用自定义的代码

    前言:本文篇幅不多,但是涉及到的内容却是开发中常用的. 涉及的内容: 1.统一设置导航控制器子控制器的返回按钮. 2.因为修改了系统的返回按钮,所以还需要设置手势事件. 3.隐藏底部的工具条. 这里直 ...

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

    在开发向苹果Apns推送消息服务功能,我们需要根据Apns接受的数据格式进行推送.下面接受我在进行apns推送时候总结的一点apns服务接受的Json数据格式 示例 1: 以下负载包含哦一个简单的 a ...

  5. iOS开发之功能模块--根据需求开发横向的子弹盒View

    这个需求是本人工作开发中后期需求要添加的新功能,本人模仿UITableView的代理和数据源方法进行了第一阶段的开发.第二阶段是添加丰富的动画. 这个功能需求描述:能上传添加五个待选头像,五个头像分别 ...

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

    不管想不想看我后面再开发中总结的经验,但是很值得推荐一位大神写的关于苹果推送,很多内容哦:http://www.cnblogs.com/qiqibo/category/408304.html 苹果开发 ...

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

    本人公司项目属于社交类,高仿Boss直聘早期的版本,现在Boss直聘界面风格,交互风格都不如Boss直聘以前版本的好看. 本人通过iPhone模拟器和本人真机对聊,将完成的交互功能通过Mac截屏模拟器 ...

  8. iOS开发之功能模块--本地序列化

    下面只展示项目开发中,本地序列化的示例代码: AuthenticationManager.h #import <Foundation/Foundation.h> #import " ...

  9. iOS开发之功能模块--计算高度Demo探究手稿

    本篇记录关于计算文本高度和Label高度的代码,以备后期再探究: 首先是YouXianMing老师的工具类别: NSString+LabelWidthAndHeight.h // // NSStrin ...

随机推荐

  1. 清除页面广告?身为前端,自己做一款简易的chrome扩展吧

    大家肯定有这样的经历,浏览网页的时候,左右两端广告,诸如“屠龙宝刀,点击就送”,以及最近火的不行的林子聪37传奇霸业什么“霸业面具,霸业吊坠”的魔性广告总是充斥我们的眼球. 当然有现成的扩展程序或者插 ...

  2. 精确率与召回率,RoC曲线与PR曲线

    在机器学习的算法评估中,尤其是分类算法评估中,我们经常听到精确率(precision)与召回率(recall),RoC曲线与PR曲线这些概念,那这些概念到底有什么用处呢? 首先,我们需要搞清楚几个拗口 ...

  3. iOS开发之远程推送

    说到远程推送,应该用的也挺多的,今天就基于SEA的云推送服务,做一个推送的小demo,来了解一下iOS中的远程推送是怎么一回事儿,首先你得有苹果的开发者账号,好咸蛋也差不多了,主要内容走起. 一.准备 ...

  4. 如何装出高逼格的64位win7系统

    自从有了ghost这个玩艺儿,装系统就不再是什么技术活了,但是一直崇尚纯净.原生.DIY的挨踢男来说,这种千篇一律的系统从来都不是他们想要的.为了榨干硬件的每一滴性能,发挥软件的最大效果,他们喜欢折腾 ...

  5. 1Z0-053 争议题目解析419

    1Z0-053 争议题目解析419 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 419.In Oracle 11g, by default which one of the fo ...

  6. git取消跟踪文件

    取消跟踪文件: $git rm --cached FILENAME 取消跟踪目录: $git rm --cached FILENAME -r

  7. Get和Post区别

    1. get是从服务器上获取数据,post是向服务器传送数据.2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过H ...

  8. 浅谈 C#委托

    看了<CLR via C#>的17章委托后,为自己做一点浅显的总结,也分享给需要的人. .NET通过委托来提供一种回调函数机制,.NET委托提供了很多功能,例如确保回调方法是类型安全的(C ...

  9. # ASP.NET Core依赖注入解读&使用Autofac替代实现

    标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...

  10. [WCF编程]12.事务:事务协议与管理器

    一.事务协议 总体来说,WCF开发人员不需要涉及事务协议与管理器.我们应该依赖WCF来选择相应的事务协议和管理器,重点关注业务逻辑的实现. WCF是根据事务范围里的参与个体来选择事务管理协议的.事务管 ...