Как правильно представить поповер из 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
}
Чтобы выскочить поповер рядом с аксессуаром, вы можете использовать этот код:)
Я использую это для более продвинутого использования:
- находит пользовательский accesoryView (cell.accesoryView)
- если пусто, найдите сгенерированный accesoryView (UIButton), если ячейка имеет
- если UIButton не существует, найдите представление контекста ячейки (UITableViewCellContentView)
- если контекстное представление ячейки не существует, используйте представление ячейки
Можно использовать для 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];