这是个很有用的列别工具类,在聊天对话框添加和QQ一样的"复制、粘贴、取消"等选项,而且使用起来很方便,只要找到聊天泡泡内部的某个View,比如Label或者背景冒泡的UIImageView,直接add...即可实现下面的效果:

直接上源码:

UIView+PressMenu.h

 #import <UIKit/UIKit.h>

 @interface UIView (PressMenu)
@property (strong, nonatomic) NSArray *menuTitles;
@property (strong, nonatomic) UILongPressGestureRecognizer *pressGR;
@property (copy, nonatomic) void(^menuClickedBlock)(NSInteger index, NSString *title);
@property (strong, nonatomic) UIMenuController *menuVC; - (void)addPressMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block;
- (void)showMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block; - (BOOL)isMenuVCVisible;
- (void)removePressMenu;
@end

UIView+PressMenu.m

 #import "UIView+PressMenu.h"
#import <objc/runtime.h> @implementation UIView (PressMenu) static const NSString *kPressMenuSelectorPrefix = @"easePressMenuClicked_";
static char PressMenuTitlesKey, PressMenuBlockKey, PressMenuGestureKey, MenuVCKey; #pragma mark M
- (void)addPressMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block{
self.userInteractionEnabled = YES;
self.menuClickedBlock = block;
self.menuTitles = menuTitles;
if (self.pressGR == nil) {
self.pressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePress:)];
}
[self addGestureRecognizer:self.pressGR];
} - (void)showMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block{
self.menuClickedBlock = block;
self.menuTitles = menuTitles;
[self p_showMenu];
} - (BOOL)isMenuVCVisible{
if (self.menuVC) {
return [self.menuVC isMenuVisible];
}
return NO;
} - (void)removePressMenu{
if (self.menuVC) {
[self.menuVC setMenuVisible:NO animated:YES];
self.menuVC = nil;
}
if ([self.pressGR isKindOfClass:[UILongPressGestureRecognizer class]]) {
[self removeGestureRecognizer:self.pressGR];
self.pressGR = nil;
}
if (self.menuClickedBlock) {
self.menuClickedBlock = nil;
}
if (self.menuTitles) {
self.menuTitles = nil;
}
} #pragma mark SET_GET
- (void)setMenuTitles:(NSArray *)menuTitles{
objc_setAssociatedObject(self, &PressMenuTitlesKey, menuTitles, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSArray *)menuTitles{
return objc_getAssociatedObject(self, &PressMenuTitlesKey);
} - (void)setMenuClickedBlock:(void (^)(NSInteger, NSString *))menuClickedBlock{
objc_setAssociatedObject(self, &PressMenuBlockKey, menuClickedBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void (^)(NSInteger, NSString *))menuClickedBlock{
return objc_getAssociatedObject(self, &PressMenuBlockKey);
} - (void)setPressGR:(UILongPressGestureRecognizer *)pressGR{
objc_setAssociatedObject(self, &PressMenuGestureKey, pressGR, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UILongPressGestureRecognizer *)pressGR{
return objc_getAssociatedObject(self, &PressMenuGestureKey);
} - (void)setMenuVC:(UIMenuController *)menuVC{
objc_setAssociatedObject(self, &MenuVCKey, menuVC, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIMenuController *)menuVC{
return objc_getAssociatedObject(self, &MenuVCKey);
} #pragma mark canPerformAction
- (BOOL)canBecomeFirstResponder{
if (self.menuClickedBlock) {
return YES;
}else{
return [super canBecomeFirstResponder];
}
} -(BOOL)canPerformAction:(SEL)action withSender:(id)sender{
if (self.menuClickedBlock) {
for (int i=; i<self.menuTitles.count; i++) {
if (action == NSSelectorFromString([NSString stringWithFormat:@"%@%d:", kPressMenuSelectorPrefix, i])) {
return YES;
}
}
return NO;
}else{
return [super canPerformAction:action withSender:sender];
}
} -(void)handlePress:(UIGestureRecognizer*)recognizer{
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self p_showMenu];
}
} - (void)p_showMenu{
[self becomeFirstResponder];
NSMutableArray *menuItems = [[NSMutableArray alloc] initWithCapacity:self.menuTitles.count];
Class cls = [self class];
SEL imp = @selector(pressMenuClicked:);
for (int i=; i<self.menuTitles.count; i++) {
NSString *title = [self.menuTitles objectAtIndex:i];
//注册名添加方法sel,sel的具体实现在imp(pressMenuClicked:)
SEL sel = sel_registerName([[NSString stringWithFormat:@"%@%d:", kPressMenuSelectorPrefix, i] UTF8String]);
class_addMethod(cls, sel, [cls instanceMethodForSelector:imp], "v@");
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:title action:sel];
[menuItems addObject:menuItem];
}
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:menuItems];
[menu setTargetRect:self.frame inView:self.superview];
[menu setMenuVisible:YES animated:YES];
self.menuVC = menu;
} - (void)pressMenuClicked:(id)sender {
NSString *selStr = NSStringFromSelector(_cmd);
NSString *indexStr = [selStr substringFromIndex:kPressMenuSelectorPrefix.length];
NSInteger index = indexStr.integerValue;
if (index >= && index<self.menuTitles.count) {
NSString *title = [self.menuTitles objectAtIndex:index];
if (self.menuClickedBlock) {
self.menuClickedBlock(index, title);
}
}
} @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. 关于skip_name_resolve参数的总结

    作为MySQL调优的一部分,很多人都推荐开启skip_name_resolve.这个参数是禁止域名解析的(当然,也包括主机名).很多童鞋会好奇,这背后的原理是什么,什么情况下开启这个参数比较合适. 基 ...

  2. IOS 开发中要注意的事项

    1.关于拍摄 TGCameraViewController – 基于 AVFoundation 的自定义相机.样式漂亮,轻量并且可以很容易地集成到 iOS 项目中.不会内存吃紧 2.block 中对控 ...

  3. hibernate笔记--使用注解(annotation)方式配置单(双)向多对一的映射关系

    前面几篇都是介绍的用配置文件来实现实体类到数据库表的映射,这种方式是比较麻烦的,每一个pojo类都需要写一个相应的*.hbm.xml,无疑增加了很多代码量,不过也有优点就是利于维护,为了方便开发,Hi ...

  4. MySQL的多存储引擎架构

    支持多种存储引擎是众所周知的MySQL特性,也是MySQL架构的关键优势之一.如果能够理解MySQL Server与存储引擎之间是怎样通过API交互的,将大大有利于理解MySQL的核心基础架构.本文将 ...

  5. PHP中curl_init函数用法

    使用PHP的cURL库可以简单和有效地去抓网页.你只需要运行一个脚本,然后分析一下你所抓取的网 页,然后就可以以程序的方式得到你想要的数据了.无论是你想从从一个链接上取部分数据,或是取一个XML文件并 ...

  6. 淘宝购物车页面 智能搜索框Ajax异步加载数据

    如果有朋友对本篇文章的一些知识点不了解的话,可以先阅读此篇文章.在这篇文章中,我大概介绍了一下构建淘宝购物车页面需要的基础知识. 这篇文章主要探讨的是智能搜索框Ajax异步加载数据.jQuery的社区 ...

  7. 记dynamic的一个小坑 -- RuntimeBinderException:“object”未包含“xxx”的定义

    创建一个控制台程序和一个类库, 在控制台创建一个匿名对象,然后再在类库中访问它,代码如下: namespace ConsoleApplication1 { class Program { static ...

  8. EF Fluent API上

     什么是Fluent API? 官方答案:EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体映射到约定指示外的其他对象,所以Fluent API和注解都是一种方 ...

  9. 一个简单得不能再简单的“ORM”了

    本文适合初学者,老鸟请点赞即走,谢谢. 文字功底有限,表述不恰当的地方,请各位多多包涵. 一,核心 现在ORM已经很多了,功能也齐全了,大家说我这是干无聊的事,造的连车轮子都还不算,反正我就当学习. ...

  10. 原生js文字标签云上下滚动播放

    效果:http://hovertree.com/texiao/js/25/ 效果图: 代码如下: <!DOCTYPE html> <html> <head>< ...