Как правильно представить поповер из UITableViewCell с помощью UIPopoverArrowDirectionRight или UIPopoverArrowDirectionLeft

Я всегда пытаюсь представить поповер из ячейки внутри tableView следующим образом:

[myPopover presentPopoverFromRect:cell.frame inView:self.tableView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

но я не могу использовать UIPopoverArrowDirectionRight или Left, потому что, в зависимости от положения ipad (книжная или альбомная), поповер появляется в другом месте.

Я правильно представляю поповер?

PS: табличное представление находится в подробном представлении splitView.

11 ответов

Решение

Вот простое решение, которое отлично работает для меня

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    CGRect rect=CGRectMake(cell.bounds.origin.x+600, cell.bounds.origin.y+10, 50, 30);
    [popOverController presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

}

Вы получаете кадр из ячейки с помощью метода rectForRowAtIndexPath. Это правильно. Однако табличное представление, скорее всего, является подпредставлением более крупного iPad-представления, поэтому, когда поповер получает координаты, он думает, что он находится в более крупном представлении. Вот почему поповер появляется не в том месте.

Например, CGRect для строки (0,40,320,44). Вместо всплывающего окна, нацеленного на этот кадр в табличном представлении, оно вместо этого предназначается для этого кадра в главном представлении.

Я решил эту проблему путем преобразования кадра из относительных координат таблицы в координаты в моем увеличенном виде.

код:

CGRect aFrame = [self.myDetailViewController.tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:theRow inSection:1]];
[popoverController presentPopoverFromRect:[self.myDetailViewController.tableView convertRect:aFrame toView:self.view] inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];

Надеюсь, что это помогает другим, ищущим эту проблему.

В Swift, между ответами выше, это работает для меня на iPad в любой ориентации:

if let popOverPresentationController : UIPopoverPresentationController = myAlertController.popoverPresentationController {

    let cellRect = tableView.rectForRowAtIndexPath(indexPath)

    popOverPresentationController.sourceView                = tableView
    popOverPresentationController.sourceRect                = cellRect
    popOverPresentationController.permittedArrowDirections  = UIPopoverArrowDirection.Any

}

Я столкнулся с этой проблемой сегодня, и я нашел более простое решение.
При создании экземпляра popover необходимо указать представление содержимого ячейки:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIViewController *aViewController = [[UIViewController alloc] init];
    // initialize view here

    UIPopoverController *popoverController = [[UIPopoverController alloc] 
        initWithContentViewController:aViewController];
    popoverController.popoverContentSize = CGSizeMake(320, 416);
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [popoverController presentPopoverFromRect:cell.bounds inView:cell.contentView 
        permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

    [aView release];
    // release popover in 'popoverControllerDidDismissPopover:' method
}

Чтобы выскочить поповер рядом с аксессуаром, вы можете использовать этот код:)

Я использую это для более продвинутого использования:

  1. находит пользовательский accesoryView (cell.accesoryView)
  2. если пусто, найдите сгенерированный accesoryView (UIButton), если ячейка имеет
  3. если UIButton не существует, найдите представление контекста ячейки (UITableViewCellContentView)
  4. если контекстное представление ячейки не существует, используйте представление ячейки

Можно использовать для UIActionSheet или UIPopoverController.

Вот мой код:

UIView *accessoryView       = cell.accessoryView; // finds custom accesoryView (cell.accesoryView)
if (accessoryView == nil) {
    UIView *cellContentView = nil;

    for (UIView *accView in [cell subviews]) {
        if ([accView isKindOfClass:[UIButton class]]) {
            accessoryView   = accView; // find generated accesoryView (UIButton) 
            break;
        } else if ([accView isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) {
            // find generated UITableViewCellContentView                
            cellContentView = accView; 
        }
    }
    // if the UIButton doesn't exists, find cell contet view (UITableViewCellContentView)           
    if (accessoryView == nil) { 
        accessoryView   = cellContentView; 
    }
    // if the cell contet view doesn't exists, use cell view
    if (accessoryView == nil) {
        accessoryView   = cell; 
    }
}

[actionSheet showFromRect:accessoryView.bounds inView:accessoryView animated:YES];

Протестировано в iOS 4.3 до 5.1

Лучше всего использовать в качестве пользовательского метода:

-(UIView*)getViewForSheetAndPopUp:(UITableViewCell*)cell;

И код метода:

-(UIView*)getViewForSheetAndPopUp:(UITableViewCell*)cell {
UIView *accessoryView = cell.accessoryView;

if (accessoryView == nil) {
    UIView *cellContentView = nil;

    for (UIView *accView in [cell subviews]) {
        if ([accView isKindOfClass:[UIButton class]]) {
            accessoryView = accView;
            break;
        } else if ([accView isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) {              
            cellContentView = accView;
        }
    }       

    if (accessoryView == nil) {
        accessoryView   = cellContentView;
    }
    if (accessoryView == nil) {
        accessoryView   = cell;
    }
}

return accessoryView;
}

Я тоже сталкивался с этой проблемой. Решением для меня было просто изменить ширину прямоугольника, возвращаемого CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath:

CGRect rect = [aTableView rectForRowAtIndexPath:indexPath];

//create a 10 pixel width rect at the center of the cell

rect.origin.x = (rect.size.width - 10.0) / 2.0; 
rect.size.width = 10.0;  

[self.addExpensePopoverController presentPopoverFromRect:rect inView:aTableView permittedArrowDirections:UIPopoverArrowDirectionAny  animated:YES]; 

Это создает прямоугольник с центром внутри ячейки. Таким образом, у поповера больше шансов найти хорошее место для позиционирования.

У меня была такая же проблема, вот обходной путь, который я использовал:

  • в моем UITableViewCell я добавил Действия (IBActions, поскольку я генерирую свои ячейки из NIB) для определенных кнопок ячейки.
  • Затем я определил протокол CellActionDelegate, который имитирует мои селекторы действий, к которым у меня были кнопка (отправитель) и ячейка (я)
  • тогда detailViewController моего splitViewController реализует этот протокол, преобразовывая ячейку в ее координаты...

вот пример кода

В MyCustomTableViewCell.m:

   -(IBAction)displaySomeCellRelativePopover:(id)sender{
        //passes the actions to its delegate
        UIButton *button = (UIButton *)sender;
        [cellActionDelegate displaySomeCellRelativePopoverWithInformation:self.info
                                                               fromButton:button 
                                                                 fromCell:self];   
   }

и, в MyDetailViewController.m:

-(void)displaySomeCellRelativePopoverWithInformation:(MyCellInformationClass *)info
                                          fromButton:(UIButton *)button 
                                            fromCell:(UIView *)cell{

UIPopoverController * popoverController = nil;

//create your own UIPopoverController the way you want

//Convert your button/view frame

CGRect buttonFrameInDetailView = [self.view convertRect:button.frame fromView:cell];

//present the popoverController
[popoverController presentPopoverFromRect:buttonFrameInDetailView
                               inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];]


//release objects created...
}

PS: Конечно, "действие" не обязательно должно быть IBAction, а фрейм, из которого происходит всплывающее окно, не обязательно должен быть UIButton - один UIView был бы хорош:)

Фрейм ячейки будет примерно 0,0, ширина, размер, я не верю, что он будет иметь свои X и Y относительно tableView... вы хотите использовать - (CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath для это, это должно вернуть вам правильный кадр для ячейки относительно tableView... вот ссылка UITAbleView ref

Принятый ответ не может быть скомпилирован.

CGRect rect =[tableView rectForRowAtIndexPath:indexPath]; //This is how to get the correct position on the tableView    
UIPopoverPresentationController *popController = [controller popoverPresentationController];
popController.sourceRect = rect;
popController.permittedArrowDirections = 0;  //Here there is no arrow. It is my app's need
popController.delegate = self;
popController.sourceView = self.tableView;
popController.sourceView.backgroundColor = [UIColor yellowColor];

Вот как я это сделал и работает отлично.

RidersVC *vc = [RidersVC ridersVC];
vc.modalPresentationStyle = UIModalPresentationPopover;
vc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
UIPopoverPresentationController *popPresenter = [vc popoverPresentationController];
popPresenter.sourceView = vc.view;
popPresenter.barButtonItem= [[UIBarButtonItem alloc] initWithCustomView:button];
popPresenter.backgroundColor = [UIColor colorWithRed:220.0f/255.0f green:227.0f/255.0f blue:237.0f/255.0f alpha:1.0];
[self.parentVC presentViewController:vc animated:YES completion:NULL];

Это также сработало для меня:

        // Каковы координаты ABSOLUTE в текущей выбранной ячейке
        CGRect frame =[self.view convertRect:[tbvEventsMatch rectForRowAtIndexPath:indexPath] fromView:tbvEventsMatch.viewForBaselineLayout];
Другие вопросы по тегам