UIMenuController——颜婧

什么是UIMenuController?

UIMenuController是UIKit里面的控件

UIMenuController的作用在开发中弹出的菜单栏

后面介绍了菜单栏显示中文的设置


有哪些控件是自带UIMenuController菜单栏效果的呢?

  • UITextField
  • UITextView
  • UIWebView

主要介绍两种:

一种是控制器为第一响应者

另一种是当前UI控件为第一响应者 (把方法封装在控件里面)

具体看代码,注释里我会详细讲解,如果实在不懂不妨动手敲一遍

  1. @interface ViewController ()  
  2. @property (weak, nonatomic) IBOutlet UILabel *label;  
  3. @end  
  4.    
  5. @implementation ViewController  
  6.    
  7. - (void)viewDidLoad {  
  8.     [super viewDidLoad];  
  9.    
  10.     //首先要允许label可以跟用户交互  
  11.     self.label.userInteractionEnabled = YES;  
  12.     //给label添加一个敲击手势  
  13.     [self.label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelClick)]];  
  14. }  
  15.    
  16. /** 点击label触发的方法 */  
  17. - (void)labelClick  
  18. {  
  19.     //控制器不需要调用这个方法, 但是其他乱七八糟的UI控件就需要调用这个方法 \  
  20.     因为控制器默认是第一响应者  
  21.     //[self becomeFirstResponder];  
  22.    
  23.     //显示menu 从来没有让menu跟控制器有关系 , 因为是第一响应者, 所以会调用第一响应者的方法  
  24.    
  25.     //不一定调用控制器的方法, 因为现在控制器是第一响应者  
  26.    
  27.    
  28.    
  29.     // 获得菜单  
  30.     UIMenuController *menu = [UIMenuController sharedMenuController];  
  31.    
  32.     // 菜单最终显示的位置  
  33.     CGRect rect = CGRectMake(100, 100, 100, 100);  
  34.     [menu setTargetRect:rect inView:self.label];  
  35.     //为什么要设置2个参数  为了通用 \  
  36.     一个是矩形框, 一个是在哪个View上面  
  37.     //传了矩形框, 要告诉坐标原点在哪, 坐标原点就在view上\  
  38.     以tagreView的左上角为坐标原点  
  39.     // 苹果设计2个参数 是因为矩形框一旦修改 出现的位置在哪里都是可以的  
  40.    
  41.     /*  
  42.      targetRect:menuController指向的矩形框  
  43.      targetView:targetRect以targetView的左上角为坐标原点  
  44.      */  
  45.    
  46.     // 显示菜单  
  47.     [menu setMenuVisible:YES animated:YES];  
  48.    
  49.     /*  
  50.      得通过第一响应者,来告诉MenuController它内部应该显示什么内容  
  51.      */  
  52. }  
  53.    
  54. #pragma mark - 第一响应者 + UIMenuController  
  55. /**  
  56.  * 说明控制器可以成为第一响应者  
  57.  * 因为控制器是因为比较特殊的对象,它找控制器的方法,不找label的方法  
  58.  */  
  59. - (BOOL)canBecomeFirstResponder  
  60. {  
  61.     return YES;  
  62. }  
  63.    
  64. /**  
  65.  * 通过这个方法告诉UIMenuController它内部应该显示什么内容  
  66.  * 返回YES,就代表支持action这个操作  
  67.  */  
  68. - (BOOL)canPerformAction:(SEL)action withSender:(id)sender  
  69. {  
  70.     //打印, 将一个方法转换成字符串 你就会看到许多方法  
  71.     NSLog(@"%@",NSStringFromSelector(action));  
  72.    
  73.        if (action == @selector(cut:)  
  74.         || action == @selector(copy:)  
  75.         || action == @selector(paste:)) {  
  76.         return YES;  
  77.     }  
  78.    
  79.     return NO;  
  80. }  
  81.    
  82. //监听事情需要对应的方法 冒号之后传入的是UIMenuController  
  83. - (void)cut:(UIMenuController *)menu  
  84. {  
  85.     NSLog(@"%s %@", __func__, menu);  
  86. }  
  87.    
  88. - (void)copy:(UIMenuController *)menu  
  89. {  
  90.     NSLog(@"%s %@", __func__, menu);  
  91. }  
  92.    
  93. - (void)paste:(UIMenuController *)menu  
  94. {  
  95.     NSLog(@"%s %@", __func__, menu);  
  96. }  
上面只是简单的介绍了UIMenuController的基本知识,下面正在带你运用到开发中的知识,封装一个自定义控件里面实现, 附上大概效果:


上代码,代码有具体的注释,还有具体的用法,所以认真阅读代码即可,就不附上demo了

[html]  view plain  copy
  1. #import "JHLabel.h"  
  2.    
  3. @implementation JHLabel  
  4.    
  5. /** 不管控件是通过xib stroyboard 还是纯代码  提供两种初始化的操作都调用同一个方法 */  
  6. - (instancetype)initWithFrame:(CGRect)frame  
  7. {  
  8.     if (self = [super initWithFrame:frame]) {  
  9.         [self setupTap];  
  10.     }  
  11.     return self;  
  12. }  
  13. /** 不管控件是通过xib stroyboard 还是纯代码  提供两种初始化的操作都调用同一个方法 */  
  14. - (void)awakeFromNib  
  15. {  
  16.     [self setupTap];  
  17. }  
  18. /** 设置敲击手势 */  
  19. - (void)setupTap  
  20. {  
  21.    
  22.     self.text = @"author:会跳舞的狮子";  
  23.     //已经在stroyboard设置了与用户交互,也可以用纯代码设置  
  24. //    self.userInteractionEnabled = YES;  
  25.    
  26.     //当前控件是label 所以是给label添加敲击手势  
  27.    [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelClick)]];  
  28.    
  29. }  
  30. /** 点击label触发的方法 */  
  31. - (void)labelClick  
  32. {  
  33.     // 让label成为第一响应者 \  
  34.     一定要写这句话  因为这句话才是主动让label成为第一响应者  
  35.     [self becomeFirstResponder];  
  36.    
  37.     // 获得菜单  
  38.     UIMenuController *menu = [UIMenuController sharedMenuController];  
  39.    
  40.     // 设置菜单内容 \  
  41.     因为menuItems是数组 官方没有给出需要传入什么对象,但是以经验可以判断出需要传入的是UIMenuItem对象 \  
  42.     而且显示是按顺序的  
  43.     menu.menuItems = @[  
  44.                        [[UIMenuItem alloc] initWithTitle:@"顶" action:@selector(ding:)],  
  45.                        [[UIMenuItem alloc] initWithTitle:@"回复" action:@selector(reply:)],  
  46.                        [[UIMenuItem alloc] initWithTitle:@"举报" action:@selector(warn:)]  
  47.                        ];  
  48.    
  49.     // 菜单最终显示的位置 \  
  50.     有两种方式: 一种是以自身的bounds  还有一种是以父控件的frame   
  51.     [menu setTargetRect:self.bounds inView:self];  
  52. //    [menu setTargetRect:self.frame inView:self.superview];  
  53.    
  54.     // 显示菜单  
  55.     [menu setMenuVisible:YES animated:YES];  
  56. }  
  57.    
  58. #pragma mark - UIMenuController相关  
  59. /**  
  60.  * 让Label具备成为第一响应者的资格  
  61.  */  
  62. - (BOOL)canBecomeFirstResponder  
  63. {  
  64.     return YES;  
  65. }  
  66.    
  67. /**  
  68.  * 通过第一响应者的这个方法告诉UIMenuController可以显示什么内容  
  69.  */  
  70. - (BOOL)canPerformAction:(SEL)action withSender:(id)sender  
  71. {  
  72.     if ( (action == @selector(copy:) && self.text) // 需要有文字才能支持复制  
  73.         || (action == @selector(cut:) && self.text) // 需要有文字才能支持剪切  
  74.         || action == @selector(paste:)  
  75.         || action == @selector(ding:)  
  76.         || action == @selector(reply:)  
  77.         || action == @selector(warn:)) return YES;  
  78.    
  79.     return NO;  
  80. }  
  81.    
  82. #pragma mark - 监听MenuItem的点击事件  
  83. /** 剪切 */  
  84. - (void)cut:(UIMenuController *)menu  
  85. {  
  86.     //UIPasteboard 是可以在应用程序与应用程序之间共享的 \  
  87.     (应用程序:你的app就是一个应用程序 比如你的QQ消息可以剪切到百度查找一样)  
  88.     // 将label的文字存储到粘贴板  
  89.     [UIPasteboard generalPasteboard].string = self.text;  
  90.     // 清空文字  
  91.     self.text = nil;  
  92. }  
  93. /** 赋值 */  
  94. - (void)copy:(UIMenuController *)menu  
  95. {  
  96.     // 将label的文字存储到粘贴板  
  97.     [UIPasteboard generalPasteboard].string = self.text;  
  98. }  
  99. /** 粘贴 */  
  100. - (void)paste:(UIMenuController *)menu  
  101. {  
  102.     // 将粘贴板的文字赋值给label  
  103.     self.text = [UIPasteboard generalPasteboard].string;  
  104. }  
  105.    
  106. //如果方法不实现,是不会显示出来的  
  107. - (void)ding:(UIMenuController *)menu  
  108. {  
  109.     NSLog(@"%s %@", __func__, menu);  
  110. }  
  111.    
  112. - (void)reply:(UIMenuController *)menu  
  113. {  
  114.     NSLog(@"%s %@", __func__, menu);  
  115. }  
  116.    
  117. - (void)warn:(UIMenuController *)menu  
  118. {  
  119.     NSLog(@"%s %@", __func__, menu);  
  120. }  
  121. @end  
上面的代码,menu只显示在label的上面 而一般菜单栏我们都是显示在cell的中间, 下面的这幅图详细讲解了显示在cell的中间


[html]  view plain  copy
  1. /** 点击cell的时候调用 */  
  2. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath  
  3. {  
  4.     // 取出cell  
  5.     UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];  
  6.    
  7.     UIMenuController *menu = [UIMenuController sharedMenuController];  
  8.    
  9.     // 设置菜单内容  
  10.     menu.menuItems = @[  
  11.                        [[UIMenuItem alloc] initWithTitle:@"顶" action:@selector(ding:)],  
  12.                        [[UIMenuItem alloc] initWithTitle:@"回复" action:@selector(reply:)],  
  13.                        [[UIMenuItem alloc] initWithTitle:@"举报" action:@selector(warn:)]  
  14.                        ];  
  15.    
  16.     // 显示位置  
  17.     CGRect rect = CGRectMake(0, cell.height * 0.5, cell.width, 1);  
  18.     [menu setTargetRect:rect inView:cell];  
  19.    
  20.     // 显示出来  
  21.     [menu setMenuVisible:YES animated:YES];  
  22. }  
  23.    
  24. #pragma mark - 获得当前选中的评论  
  25. - (JHComment *)selectedComment  
  26. {  
  27.     // 获得被选中的cell的行号  
  28.     NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;  
  29.     NSInteger row = indexPath.row;  
  30.    
  31.     // 获得评论数据  
  32.     NSArray *comments = self.shortComments;  
  33.     if (indexPath.section == 0 && self.longComments.count) {  
  34.         comments = self.longComments;  
  35.     }  
  36.    
  37.     return comments[row];  
  38. }  
  39.    
  40. #pragma mark - UIMenuController处理  
  41. - (BOOL)canBecomeFirstResponder  
  42. {  
  43.     return YES;  
  44. }  
  45.    
  46. - (BOOL)canPerformAction:(SEL)action withSender:(id)sender  
  47. {  
  48.     if (!self.isFirstResponder) { // 文本框弹出键盘, 文本框才是第一响应者  
  49.         if (action == @selector(ding:)  
  50.             || action == @selector(reply:)  
  51.             || action == @selector(warn:)) return NO;  
  52.         //如果是文本框,那么这些显示都不返回  
  53.     }  
  54.    
  55.     return [super canPerformAction:action withSender:sender];  
  56. }  
  57.    
  58. - (void)ding:(UIMenuController *)menu  
  59. {  
  60.     NSLog(@"ding - %@ %@",  
  61.            self.selectedComment.user.username,  
  62.            self.selectedComment.content);  
  63. }  
  64.    
  65. - (void)reply:(UIMenuController *)menu  
  66. {  
  67.     NSLog(@"reply - %@ %@",  
  68.            self.selectedComment.user.username,  
  69.            self.selectedComment.content);  
  70. }  
  71.    
  72. - (void)warn:(UIMenuController *)menu  
  73. {  
  74.     NSLog(@"warn - %@ %@",  
  75.            self.selectedComment.user.username,  
  76.            self.selectedComment.content);  
  77. }  
  78.    
  79. #注: 这里的self.selectedComent  
  80. # (点语法  要么调用set方法要么调用get方法, 这里直接用点语法是没有提示的,我已经进行了声明)  
  81. #/** 写方法声明的目的是为了使用点语法提示 */  
  82. #- (JHComment *)selectedComment;  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值