web-dev-qa-db-fra.com

Comment présenter correctement un popover d'un UITableViewCell avec UIPopoverArrowDirectionRight ou UIPopoverArrowDirectionLeft

J'essaie toujours de présenter un popover d'une cellule à l'intérieur d'une tableVue de cette façon:

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

mais je ne peux pas utiliser UIPopoverArrowDirectionRight ou Left, car, selon la position de l'ipad (portrait ou paysage), le survol apparaît ailleurs.

Est-ce que je présente le popover de la bonne façon?

PS: la vue de table se trouve dans la vue de détail d’une vue partagée.

31
Omer

Voici la solution simple qui fonctionne bien pour moi

- (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];

}
2
vrk

Vous obtenez le cadre de la cellule via la méthode rectForRowAtIndexPath. C'est correct. Cependant, la vue de table est très probablement une sous-vue d'une vue iPad plus grande. Ainsi, lorsque la fenêtre popover obtient les coordonnées, elle pense qu'elle se trouve dans une vue plus grande. C'est pourquoi le popover apparaît au mauvais endroit. 

Par exemple, le CGRect de la ligne est (0,40,320,44). Au lieu que le popover cible cette image dans la vue de table, il cible plutôt cette image dans la vue principale. 

J'ai résolu ce problème en convertissant le cadre des coordonnées relatives de la table en coordonnées dans ma vue plus grande. 

code:

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];

J'espère que cela aidera les autres à la recherche de ce problème. 

49
John

J'ai rencontré ce problème aujourd'hui et j'ai trouvé une solution plus simple.
Lors de l’instanciation du popover, vous devez spécifier la vue du contenu de la cellule:

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

Dans Swift, entre les réponses ci-dessus, cela fonctionne pour moi sur un iPad, quelle que soit leur orientation: 

if let popOverPresentationController : UIPopoverPresentationController = myAlertController.popoverPresentationController {

    let cellRect = tableView.rectForRowAtIndexPath(indexPath)

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

}
18
Fred Faust

Pour afficher un popover à côté de l’accessoire, vous pouvez utiliser ce code :)

Je l'utilise pour plus utilisation avancée:

  1. trouve accesoryView personnalisé (cell.accesoryView)
  2. si vide, trouve accesoryView généré (UIButton) si la cellule a
  3. si le bouton UIB n'existe pas, recherchez la vue Contet de la cellule (UITableViewCellContentView).
  4. si la vue de la cellule n'existe pas, utilisez la vue de la cellule

Peut être utilisé pour UIActionSheet ou UIPopoverController .

Voici mon code:

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];

Testé sous iOS 4.3 à 5.1

Il est préférable d'utiliser comme méthode personnalisée:

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

Et code de la méthode:

-(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;
}
4
Pion

J'ai rencontré ce problème aussi. Une solution pour moi était simplement de changer la largeur du rect retourné par 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]; 

Cela crée un rect à l'intérieur de la cellule. De cette façon, le popover a plus de chances de trouver un bon emplacement pour se positionner.

3
okcompute

J'ai eu le même genre de problème, voici la solution de contournement que j'ai utilisée:

  • dans mon UITableViewCell, j'ai ajouté Actions (IBActions car je génère mes cellules à partir d'un NIB) pour les boutons spécifiques des cellules.
  • j'ai ensuite défini un protocole CellActionDelegate qui imite mes sélecteurs d'actions, auquel j'avais mon bouton (expéditeur) et mon cellulaire (auto)
  • alors le detailViewController de mon splitViewController implémente ce protocole, en convertissant les coordonnées de la cellule en ses coordonnées ...

voici un exemple de code

Dans MyCustomTableViewCell.m:

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

et le, dans 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: Bien sûr, l'action ne doit pas nécessairement être une action IBAction, et le cadre d'où provient le popover ne doit pas nécessairement être un bouton UIB - un seul UIView serait bien :)

2
Vinzzz

Le cadre de la cellule va être quelque chose comme 0,0, largeur, taille, je ne crois pas qu'il aura son X et Y par rapport à la tableView ... vous voulez utiliser - (CGRect) rectForRowAtIndexPath: (NSIndexPath *) indexPath pour ceci, ceci devrait vous retourner le bon cadre pour la cellule par rapport à la tableView ... voici un lien UITAbleView ref

2
Daniel

C'est comme ça que j'ai fait et fonctionne parfaitement bien.

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];
0
i.jameelkhan

Cela a également fonctionné pour moi:


 // Quelles sont les coordonnées ABSOLUES de la cellule actuellement sélectionnée 
 CGRect frame = [self.view convertRect: [tbvEventsMatch rectForRowAtIndexPath: indexPath] à partir de View: tbvEventsMatch.viewForBaselineLayout];

La réponse acceptée ne peut pas être compilée maintenant.

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];
0
flame3