Misplaced popover after upgrading to iOS 11

424 Views Asked by At

Since upgrading to iOS 11, I started having problems with a misplaced popover, which normally has its frame set by presentPopoverFromRect:sender.frame to the coordinates of the navigation bar button, which triggered the action.

The problem: The x and y coordinates of the (UIButton *)sender.frame are equal to {0,0} and the popover gets displayed in the upper left corner of the screen.

Here is the generateToolbar() method, which generates the user navigation button.

-(void) generateToolbar {

    // Initialize the `ButtonFactory`

    ButtonFactory *buttonFactory = [[ButtonFactory alloc] init];

    // Generate some UIButton(s)

    UIButton *userUIBtn = [buttonFactory createButtonWithButtonType:ButtonTypeUser iconVisibility:YES textVisibility:NO capitalization:NO iconSize:20 textSize:10];
    userUIBtn.frame = CGRectMake(0,0,55,20);
    [userUIBtn addTarget:self action:@selector(userButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

    // Generate an `UIBarButtonItem` with the `UIButton` as basis

    UIBarButtonItem *userBtn = [[UIBarButtonItem alloc] initWithCustomView:userUIBtn];

    // Add the `UIBarButtonItem` into the right side of the `navigationItem`

    self.navigationItem.rightBarButtonItems = [[NSArray alloc] initWithObjects: userBtn, nil];

    DDLogVerbose(@"A: generateToolbar UIButton FRAME: %@",NSStringFromCGRect(userUIBtn.frame));

}

Here is the userButtonPressed() method, which gets triggered by pressing the user button and generates a popover around that button.

- (IBAction) userButtonPressed:(UIButton *)sender {

    // Initialize the `ButtonFactory`

    ButtonFactory *buttonFactory = [[ButtonFactory alloc] init];

    // Generate some UIButtons        

    UIButton *feedbackUIBtn = [buttonFactory createButtonWithButtonType:ButtonTypeFeedback iconVisibility:YES textVisibility:YES capitalization:NO iconSize:20.0 textSize:20.0];
    [feedbackUIBtn addTarget:self action:@selector(feedbackBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
    feedbackUIBtn.frame = CGRectMake(0,50,300,50);

    // Create a `UIViewController` and add the `UIButtons` as subviews

    UIViewController *viewController = [[UIViewController alloc] init];
    [viewController.view addSubview:feedbackUIBtn];
    [viewController.view addSubview:crashUIBtn];

    // Create the `UIPopoverController`

    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    self.mainPopoverController = [[UIPopoverController alloc] initWithContentViewController:navigationController];
    self.mainPopoverController.popoverContentSize = CGSizeMake(300, 100); 

    DDLogVerbose(@"B: userButtonPressed SENDER FRAME: %@",NSStringFromCGRect(sender.frame));

    // Present the `UIPopoverController`

    [self.mainPopoverController presentPopoverFromRect:sender.frame inView:self.view permittedArrowDirections: UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionUp animated:YES];
}

The log output - in both places the x, y coordinates are equal to {0, 0}, which is wrong, they should be non-zero and equal to the actual coordinated of the UIBarButtonItem:

A: generateToolbar UIButton FRAME: {{0, 0}, {55, 20}}
B: userButtonPressed SENDER FRAME: {{0, 0}, {55, 32}}
1

There are 1 best solutions below

2
matt On

The notion "to the coordinates of the navigation bar button" makes no sense, as a UIBarButtonItem is not a UIView and has no frame. The way to point a popover arrow to a UIBarButtonItem is to set the popover presentation controller's barButtonItem. (The popover presentation controller: you should not be using UIPopoverController in this day and age.)