Как использовать Storyboard для создания popover, который может использоваться в коде?

Я создаю набор форм, каждый из которых содержит несколько полей. Некоторые из полей UITextField, которые будут отображать дату. Я создал новый класс под названием DatePickerTextField, потомок UITextField. Когда a DatePickerTextField используется, я хотел бы, чтобы элемент управления UIDatePicker отображался в popover.

Мой вопрос: как использовать раскадровку для реализации popover? Я могу сделать segue, когда на сцене есть конкретный видимый элемент управления. Но как мне представить общий popover в сцене, который я могу подключить к любому экземпляру DatePickerTextField, который станет активным?

Ответ 1

Вы можете создать segue, который не связан с каким-либо элементом управления, но я не думаю, что был бы способ указать опорную точку для popover из кода. Другой вариант - создать ViewController, который не связан с каким-либо сегментом. При редактировании раскадровки создайте ViewController, который будет помещен в popover, выберите его и перейдите в панель "Утилиты" → "Attributes Inspector". Задайте размер Freeform, Строка состояния - Нет, укажите уникальный идентификатор, который будет использоваться для создания экземпляра ViewController из кода. Теперь вы можете изменить размер ViewController, выбрав его "Просмотр" и перейдите в панель "Утилиты" → "Инспектор размеров".

После этого вы можете создать popover из кода:

- (IBAction)buttonPressed:(id)sender {
    UIView *anchor = sender;
    UIViewController *viewControllerForPopover = 
        [self.storyboard instantiateViewControllerWithIdentifier:@"yourIdentifier"];

    popover = [[UIPopoverController alloc] 
               initWithContentViewController:viewControllerForPopover];
    [popover presentPopoverFromRect:anchor.frame 
                             inView:anchor.superview 
           permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

Одно из предостережений заключается в том, что вам нужно сохранить ссылку на popover как ivar вашего класса, иначе он сработает, потому что UIPopoverController будет освобожден и освобожден после buttonPressed:

@interface MyViewController : UIViewController {
//  ...
    UIPopoverController *popover;
//  ...
}

Ответ 2

Итак, у меня была аналогичная проблема, и в случае, если другие могут принести пользу, я решил, что я поделюсь ею, так как я так сильно выигрываю от stackoverflow.

Это решение позволяет вам установить привязку настраиваемого сегмента popover. Это также позволяет настроить segue как модальный или нет (я не мог найти способ предотвратить segue, уменьшив внешний контекст, поэтому, если кто-то знает, как это сделать, мне было бы интересно услышать его); это достигается установкой представлений пересылки для контроллера popover. Я также добавил возможность указать пользовательский вид, а не представление источника viewcontroller (так как мне нужна эта емкость); эта часть не имеет решающего значения для решения.

DynamicPopoverSegue.h

@interface DynamicPopoverSegue : UIStoryboardPopoverSegue

@property BOOL isModal;
@property UIView* sourceView;
@property CGRect anchor;

@end

DynamicPopoverSegue.m

@implementation DynamicPopoverSegue

- (void)perform
{
   if (!self.popoverController.popoverVisible)
   {
      UIViewController* dst = (UIViewController*)self.destinationViewController;
      UIViewController* src = (UIViewController*)self.sourceViewController;

      UIView* inView =  _sourceView ? _sourceView : src.view;

      self.popoverController.contentViewController = dst;
      if (!_isModal)
      {
         [self.popoverController setPassthroughViews:[[NSArray alloc] initWithObjects:inView, nil]];
      }
      [self.popoverController presentPopoverFromRect:_anchor
                                              inView:inView
                            permittedArrowDirections:UIPopoverArrowDirectionAny
                                            animated:YES];
   }
}

@end

Затем вы просто установили свой segue в "Custom" в раскадровке и установите класс segue в "DynamicPopoverSegue". В моем случае, поскольку я хотел связать его с динамическими слоями в представлении, я не мог установить привязку, поэтому я создал segue, щелкнув элемент управления, щелкнув значок значка в панели под моим контроллером представления, на контроллер представления, на котором я был используя для представления popupover.

Чтобы вызвать popper segue:

[self performSegueWithIdentifier:@"MyPopoverSegue" sender:self];

И чтобы настроить popover segue:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
   if ([[segue identifier] isEqualToString:@"MyPopoverSegue"])
   {
      DynamicPopoverSegue* popoverSegue = (DynamicPopoverSegue*)segue;
      // set the anchor to wherever you want it to be
      popoverSegue.anchor = _destinationFrame;
   }
}

Ответ 3

- (IBAction)pressItemChooseOprateRoom:(id)sender {
    if (isPad){
        // UIView *anchor = sender;
        UIViewController *viewControllerForPopover =
        [self.storyboard instantiateViewControllerWithIdentifier:@"OperateRoomList"];

        _myPopover = [[UIPopoverController alloc]
                      initWithContentViewController:viewControllerForPopover];

        CGRect rc=[self getBarItemRc:sender];
        [_myPopover presentPopoverFromRect:rc
                                    inView:self.view
                  permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

        [MLControl shared].popover =self;
        // [self perfformSegueWithIdentifier:SEGUE_POP_OPERATEROOM sender:self];
    }else{
        [self iphoneOpenOperateRoomList];
        /* [self performSegueWithIdentifier:@"iPhonePushOperateRoom" sender:self];
         */
    }
}

-(void)iphoneOpenOperateRoomList{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"OperateRoomList"];
    //        if (!index.showTabBar) {
    //            vc.hidesBottomBarWhenPushed = YES;
    //        }

    [self.navigationController pushViewController:vc animated:YES];
}

Ответ 4

Просто использовал ответ от Jonnywho для моего проекта SWIFT. Если вам это нужно:

Здесь версия SWIFT:

    let anchor: UIView = sender
    var viewControllerForPopover = self.storyboard?.instantiateViewControllerWithIdentifier("GameAboutViewController") as! UIViewController?


    let popover = UIPopoverController(contentViewController: viewControllerForPopover!)
    popover.presentPopoverFromRect(anchor.frame, inView: anchor, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)