简体   繁体   中英

Position a UIView at point of tap to launch popover

In what I think is a rather clever approach to getting around the problem of launching a popover from a UITableViewRowAction , I want to position a clear UIView over the target action and use it for the sourceRect to anchor the UIPopoverPresentationController . In this case the target action is the orange "Acct" button shown in the screenshot below.

I'm using a clear UIView ( self.clearTopView ) over the entire tableview and I init the launching view ( tappedViewOverlay ) with a frame derived from (so I thought) the location of the tap ( point ) in the view and a CGSize ( tappedRectSize ). Then I add it as a subview to self.clearTopView . I'm currently coloring it black so I can find it.

As shown in the following screenshot, part of the scheme is working according to plan. tappedViewOverlay view is added, and colored appropriately. The popoverPresentationController ( thisPPC ) is launched from this view, as intended.

在此处输入图片说明

Problem is that the view is always positioned in the upper left corner of the screen, instead of the desired location, which is where the tap occurred. Here's the relevant code:

    else if ([[segue identifier] isEqualToString:@"AccountPopSegue"])
    {

        UITapGestureRecognizer *tapGestureRecognizer;

        CGPoint point = [tapGestureRecognizer locationInView:self.clearTopView];

        NSString *pointString = NSStringFromCGPoint(point);

        NSLog(@"point is located at %@",pointString);


        CGSize tappedRectSize= CGSizeMake(60,60);
        CGRect tappedRect = {point,tappedRectSize};

        NSString * tappedRectString = NSStringFromCGRect(tappedRect);

        NSLog(@"tappedRect = %@",tappedRectString);


        tappedViewOverlay = [[UIView alloc]initWithFrame:tappedRect];
        tappedViewOverlay.backgroundColor = [UIColor blackColor];

        [self.clearTopView addSubview:tappedViewOverlay];

        [self.clearTopView setUserInteractionEnabled:NO];


        NSString *tappedOverlayFrame = NSStringFromCGRect(tappedViewOverlay.frame);
        NSLog(@"tappedViewOverlay.frame = %@",tappedOverlayFrame);


        UIViewController *controller = segue.destinationViewController;
        controller.popoverPresentationController.delegate = self;
        controller.preferredContentSize = CGSizeMake(320, 186);
        UIPopoverPresentationController *thisPPC = controller.popoverPresentationController;


        thisNavController = (UINavigationController *)segue.destinationViewController;
        AccountChangeVC *acCVC = (AccountChangeVC *)thisNavController.topViewController;
        acCVC.delegate = self;

        thisPPC.sourceView = self.clearTopView;
        thisPPC.sourceRect = tappedViewOverlay.bounds;

Can someone please show me where I'm going wrong?

Edit

CoderWang pointed out an oversight in my code, so I've corrected it:

    else if ([[segue identifier] isEqualToString:@"AccountPopSegue"])
    {

        UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc]init];

        [self.clearTopView addGestureRecognizer:tapGestureRecognizer];



        CGPoint point = [tapGestureRecognizer locationInView:self.clearTopView];

        NSString *pointString = NSStringFromCGPoint(point);

        NSLog(@"point is located at %@",pointString);


        CGSize tappedRectSize= CGSizeMake(60,60);

        CGRect tappedRect = {point,tappedRectSize};

        NSString * tappedRectString = NSStringFromCGRect(tappedRect);

        NSLog(@"tappedRect = %@",tappedRectString);


        tappedViewOverlay = [[UIView alloc]initWithFrame:tappedRect];

        tappedViewOverlay.backgroundColor = [UIColor blackColor];

        [self.clearTopView addSubview:tappedViewOverlay];

        [self.clearTopView setUserInteractionEnabled:NO];


        NSString *tappedOverlayFrame = NSStringFromCGRect(tappedViewOverlay.frame);
        NSLog(@"tappedViewOverlay.frame = %@",tappedOverlayFrame);


        UIViewController *controller = segue.destinationViewController;
        controller.popoverPresentationController.delegate = self;
        controller.preferredContentSize = CGSizeMake(320, 186);
        UIPopoverPresentationController *thisPPC = controller.popoverPresentationController;


        thisNavController = (UINavigationController *)segue.destinationViewController;
        AccountChangeVC *acCVC = (AccountChangeVC *)thisNavController.topViewController;
        acCVC.delegate = self;

        thisPPC.sourceView = self.clearTopView;
        thisPPC.sourceRect = tappedViewOverlay.bounds;

This change (initialization of the tapGestureRecognizer and addition to self.clearTopView ) produces a slight change in the position of the black tappedViewOverlay view. You can see it hiding behind the "Back" nav button in the following screenshot:

在此处输入图片说明

Problem is that the 'tappedRect' is incorrect, don`t know the reason exactly. But you can try the following method to get rect for "Acct" button converted to self.clearTopView :

CGRect tappedRect = [Acct.superview convertRect:acct.frame toView:self.clearTopView];

or converted to window (as self.clearTopView is over the entire tableview):

CGRect tappedRect = [Acct.superview convertRect:acct.frame toView:nil];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM