Метод UIMenuController setTargetRect:inView: не работает в UITableView

Я показываю пользовательский UIMenuController в моем tableview вот так

введите здесь описание изображения

но проблема в том, что он отображается в центре, я хочу отобразить его поверх label, который окрашен в оранжевый цвет. Для отображения поверх label я сделал это [menu setTargetRect:CGRectMake(10, 10, 0, 0) inView:self.lbl]; ниже весь код.

Но если я показываю UIMenuController без UITableView, setTargetRect работает нормально.

Почему setTargetRect не работает с UITableView?

Документ setTargetRect говорит:

(a) Этот целевой прямоугольник (targetRect) обычно является ограничивающим прямоугольником выделения. UIMenuController размещает меню редактирования над этим прямоугольником; если там не хватает места для меню, то размещает его под прямоугольником. Указатель меню помещается в центр верхней или нижней части целевого прямоугольника в зависимости от ситуации.

(b) Обратите внимание, что если вы сделаете ширину или высоту целевого прямоугольника нулевой, UIMenuController обрабатывает целевую область как линию или точку для позиционирования (например, курсор вставки или одиночную точку).

(c) После установки целевой прямоугольник не отслеживает представление; если представление перемещается (например, в представлении прокрутки), вы должны соответствующим образом обновить целевой прямоугольник.

Что мне не хватает?

Мойвиевконтроллер

-(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
}

Моя индивидуальная ячейка

- (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");
}

person S.J    schedule 02.07.2015    source источник
comment
Я почти уверен, что, поскольку вы пытаетесь использовать пользовательский прямоугольник, вы должны вернуть NO для shouldShowMenuForRowAtIndexPath, что также сделает ненужными методы canPerformAction и performAction.   -  person Andrew    schedule 04.07.2015
comment
Единственное, что меня беспокоит, это то, что метка не была бы вставлена ​​в иерархию представлений во время настройки UIMenuController, что может быть проблемой. Вам возможно потребуется переместить код конфигурации UIMenuController в другой метод делегата, такой как tableView:willDisplayCell, или даже в метод UIView ячейки didMoveToSuperview, чтобы убедиться, что ячейка действительно находится на экране, прежде чем установить ваш пользовательский прямоугольник.   -  person Andrew    schedule 04.07.2015
comment
@SantaClaus Нет, ничего не работает, мое меню все еще отображается в центре.   -  person S.J    schedule 04.07.2015


Ответы (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 и реализуйте эти методы.

- (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"); }
person Moiz Irshad    schedule 06.07.2015
comment
Чтобы получить cell в menuControllerWillShow, вот код: let menuOrigin = self.view.convertPoint(menuController.menuFrame.origin, toView: self.tableView) let indexPath = _chatTableView.indexPathForRowAtPoint(menuOrigin) let cell = _chatTableView.cellForRowAtIndexPath(indexPath!) - Код Swift - person D4ttatraya; 25.03.2016
comment
Это действительно работает, но допустим, что выбранное целевое меню является копией текста, затем я хочу вставить его в окно чата в поле uitextview/uitext в нижней части того же экрана, uimenucontroller будет по-прежнему отображаться и плавать в предыдущем целевом прямоугольнике. Это происходит только в том случае, если текстовое поле для вставки находится на том же экране, а не в том же табличном представлении. Любое решение для этого? - person John; 05.01.2019
comment
Хорошая работа ???????? ✅ - person Zeeshan; 23.01.2019