【问题标题】:UIMenuController method setTargetRect:inView: not working in UITableViewUIMenuController 方法 setTargetRect:inView: 在 UITableView 中不起作用
【发布时间】:2015-07-02 11:50:51
【问题描述】:

我正在像这样在我的tableview 中显示自定义UIMenuController

但问题是它显示在中心我想将它显示在橙色的label 之上。为了在label 上显示,我做了这个[menu setTargetRect:CGRectMake(10, 10, 0, 0) inView:self.lbl]; 下面是整个代码。

但如果我在没有UITableView 的情况下显示UIMenuController setTargetRect 工作正常。

为什么setTargetRect 不能与UITableView 一起使用?

setTargetRect 文档说:

(a) 这个目标矩形(targetRect)通常是边界矩形 的一个选择。 UIMenuController 将编辑菜单放置在此上方 长方形;如果那里的菜单没有足够的空间,它 将其定位在矩形下方。菜单的指针位于 目标矩形的顶部或底部的中心(视情况而定)。

(b) 请注意,如果您使目标矩形的宽度或高度 零,UIMenuController 将目标区域视为一条线或点 定位(例如,插入符号或单个点)。

(c) 一旦设置,目标矩形不跟踪视图;如果 视图移动(例如在滚动视图中发生),您必须更新 相应的目标矩形。

我错过了什么?

MyViewController

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 5;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TheCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cid" forIndexPath:indexPath];

    cell.lbl.text = [NSString stringWithFormat:@"%ld", (long)indexPath.row];

    return cell;
}

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

-(BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    return YES;
}

- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    // required
}

MyCustomCell

- (void)awakeFromNib {
    // Initialization code

    UIMenuItem *testMenuItem = [[UIMenuItem alloc] initWithTitle:@"Test" action:@selector(test:)];
    UIMenuController *menu = [UIMenuController sharedMenuController];
    [menu setMenuItems: @[testMenuItem]];

    [menu setTargetRect:CGRectMake(10, 10, 0, 0) inView:self.lbl];

    [menu update];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

-(BOOL) canPerformAction:(SEL)action withSender:(id)sender {
    return (action == @selector(copy:) || action == @selector(test:));
}

/// this methods will be called for the cell menu items
-(void) test: (id) sender {
    NSLog(@"test");
}

-(void) copy:(id)sender {
    UIMenuController *m = sender;
    NSLog(@"copy");
}

【问题讨论】:

  • 我很确定,因为您正在尝试使用自定义矩形,因此您应该为 shouldShowMenuForRowAtIndexPath 返回 NO,这也将使 canPerformActionperformAction 方法变得不必要。
  • 我唯一担心的是在您配置UIMenuController 时标签不会插入到视图层次结构中,这可能是个问题。您可能需要将UIMenuController 配置代码移动到不同的委托方法,例如tableView:willDisplayCell,或者甚至可能在单元格的UIView 方法didMoveToSuperview 中,以确保单元格实际上处于打开状态设置自定义矩形之前的屏幕。
  • @SantaClaus 没有任何效果,我的菜单仍然出现在中心。

标签: ios objective-c uitableview uimenucontroller


【解决方案1】:

1) 首先,请在您的视图控制器的viewDidLoad 方法中执行此操作。

 UIMenuItem *testMenuItem = [[UIMenuItem alloc] initWithTitle:@"Test"
    action:@selector(test:)];
[[UIMenuController sharedMenuController] setMenuItems: @[testMenuItem]];
 [[UIMenuController sharedMenuController] update];

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuControllerWillShow:) name:UIMenuControllerWillShowMenuNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuControllerWillHide:) name:UIMenuControllerWillHideMenuNotification object:nil];

2) 然后,添加这两个方法。并将menuFrame inView 设置为您的单元格

-(void)menuControllerWillShow:(NSNotification *)notification{
 //Remove Will Show Notification to prevent
 // "menuControllerWillShow" function to be called multiple times
 [[NSNotificationCenter defaultCenter]removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil];

//Hide the Original Menu View
UIMenuController* menuController = [UIMenuController sharedMenuController];
CGSize size = menuController.menuFrame.size;
CGRect menuFrame;
menuFrame.origin.x = self.tableView.frame.origin.x;
menuFrame.size = size;
[menuController setMenuVisible:NO animated:NO];

//Modify its target rect and show it again to prevent glitchy appearance
   [menuController setTargetRect:menuFrame inView:cell];
    [menuController setMenuVisible:YES animated:YES];
}

 -(void)menuControllerWillHide:(NSNotification *)notification{
    //re-register menuControllerWillShow
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuControllerWillShow:)
 name:UIMenuControllerWillShowMenuNotification object:nil];
 }

3) 实现 tableView Delegates 并实现这些方法。

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell = (TableViewCell*)[tableView cellForRowAtIndexPath:indexPath];

    return YES;
}
-(BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    return NO;
}
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    // required
}

4) 设置单元格(子类化 UITableViewCell)

 -(BOOL) canPerformAction:(SEL)action withSender:(id)sender {
    return (action == @selector(copy:) || action == @selector(test:)); } /// this methods will be called for the cell menu items
 -(void) test: (id) sender {
     NSLog(@"test"); }

 -(void) copy:(id)sender {
   NSLog(@"copy"); }

【讨论】:

  • 要在menuControllerWillShow 中获取cell,这里是代码:let menuOrigin = self.view.convertPoint(menuController.menuFrame.origin, toView: self.tableView) let indexPath = _chatTableView.indexPathForRowAtPoint(menuOrigin) let cell = _chatTableView.cellForRowAtIndexPath(indexPath!) - Swift 代码
  • 这确实有效,但是假设选择的目标菜单是复制文本,然后我想粘贴到同一屏幕底部的 uitextview/uitextfield 的聊天框中,uimenucontroller 仍将显示并漂浮在先前的目标矩形上。这只发生在要粘贴的文本字段在同一个屏幕上,而不是在同一个表视图中。有什么解决办法吗?
  • 干得好??✅
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多