iPad нестандартный размер модального контроллера представления

У меня есть несколько контроллеров модального представления определенного размера. Я пытаюсь избежать использования пользовательских представлений (создание полноэкранного черного полупрозрачного наложения поверх текущего представления, добавление модального представления к этому представлению, выполнение анимации и т. Д.), Чтобы представить его, потому что нет modalPresentationStyle, который соответствует размеру моего контроллеры.

Теперь я использую UIModalPresentationPageSheet, но мой вид меньше по высоте, и у меня есть уродливое пустое пространство

Желаемая презентация

 _______________
|    _______    |
|   |       |   |
|   |  MyVC |   |
|   |       |   |
|    -------    |
 --------------- 

Фактическая презентация

 _______________
|   |       |   |
|   |  MyVC |   |
|   |       |   |
|   |-------|   |
|   | blank |   |
 ---------------    

Если я использую UIModalPresentationFormSheet, контейнер будет меньше по ширине.

Я пытаюсь понять, как это сделать, но не знаю, возможно ли это. Каково решение проблемы представления модального виртуального канала меньшего размера, чем любой из стилей презентации? Единственное решение - организовать «настраиваемый движок контроллера модального представления»? Popovers не соответствует моим требованиям к дизайну :(


person emenegro    schedule 21.07.2010    source источник
comment
Было бы неплохо, если бы вы приняли правильный ответ на свой вопрос, щелкнув серую галочку рядом с ним.   -  person Rajesh    schedule 11.02.2014


Ответы (13)


Как и у некоторых других пользователей, у меня также была проблема, связанная с неправильным происхождением контроллера модального представления. После некоторых экспериментов я нашел решение, которое сработало для меня:

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];   
    self.view.superview.bounds = CGRectMake(0, 0, <width>, <height>);
}
person Lensflare    schedule 23.01.2013
comment
У меня это работает. Он правильно центрирует лист формы с измененным размером в iOS 6. - person James Richards; 07.02.2013
comment
Также работает с iOS 7 - person Renexandro; 08.11.2013
comment
Я бы добавил, что если вам нужно несколько раз изменить размер представления во время его отображения (например, развернуть / свернуть), вам нужно установить член класса для хранения CGRect, тогда на willLayoutSubviews вам нужно добавить if( CGRectIsEmpty( myRect ) ) { myRect = CGRectMake( 0, 0, <width>, <height> ); ) } self.view.superview.bounds = myRect; viewWillLayoutSubviews вызывается каждый когда вы обновляете супервизор, происходят странные вещи, если вы пытаетесь изменить его размер чаще, чем при начальной загрузке представления. - person Chris Ostmo; 07.01.2014
comment
@Renexandro не работает на iOS7. Когда я устанавливаю размер прямоугольника, он появляется в этом размере на секунду и мигает до размера по умолчанию. - person Gon; 13.02.2014
comment
@Gon Это действительно работает, я использовал этот простой подход в разных приложениях с iOS 7. Чтобы он работал, убедитесь, что в вашем файле XIB или раскадровке нет другого размера, также проверьте код, в котором вы у вас есть метод presentViewController, у вас нет размера, определенного для фрейма. Короче говоря, пусть метод viewWillLayoutSubviews будет единственным, что задает размер кадра модального окна, и не забудьте оставить параметры X и Y равными 0. - person Renexandro; 13.02.2014
comment
Это не сработает, если вы поместите в представление хотя бы 1 редактируемый UITextField. Когда вы пытаетесь перейти в режим редактирования, фреймворк пытается показать клавиатуру, и система заходит в бесконечный цикл! - person Magurizio; 24.09.2014
comment
Это предотвращает вращение моего модального окна. - person cnotethegr8; 23.11.2015
comment
@ cnotethegr8 попробуйте переопределить метод viewWillTransitionToSize:withTransitionCoordinator: так же, как viewWillLayoutSubviews, и посмотрите, поможет ли это с вращением. - person Lensflare; 23.11.2015
comment
Это тоже не работает. После поворота события касания не распознаются. Я предполагаю, что это что-то еще в моем приложении, так как я единственный, кто сталкивается с этой проблемой. Просто странно, как это происходит только при установке рамки модальных окон и ее вращении. Однако использование .preferredContentSize работает для меня так, как ожидалось. - person cnotethegr8; 24.11.2015

Я получил следующий результат (текст ссылки), используя:

self.modalPresentationStyle = UIModalPresentationFormSheet;

и представив его как контроллер модального представления. Сообщите мне, если вам понадобится дополнительная помощь.

person marcio    schedule 02.08.2010
comment
Спасибо за ответ, но FormSheet мне не подходит (я сказал в вопросе). - person emenegro; 02.08.2010
comment
вы можете настроить рамку в viewDidAppear - person marcio; 02.08.2010
comment
Это работает, но тень равна исходной рамке листа формы. Но ... это хороший подход. Спасибо, если никто не ответит, награда твоя;) - person emenegro; 02.08.2010
comment
Плохая сторона этого заключается в том, что Apple не документирует это, поэтому ... :( - person emenegro; 03.08.2010
comment
Пожалуйста, просмотрите мой ответ ниже, он дает вам контроль над размером модального окна. - person Brenden; 13.11.2012
comment
В вашем примере кода self является модальным VC или представляющим VC? Попытка обоих не сработала. - person abc123; 19.03.2013
comment
Чтобы изменить размер, используйте self.view.superview.frame в методе viewDidAppear - person Rambatino; 07.06.2013

Все эти ответы не будут работать с ios8 SDK.

Это будет работать:

AboutViewController * _aboutViewController = [[AboutViewController alloc] init];
    _aboutViewController.modalPresentationStyle = UIModalPresentationFormSheet;
    if(IS_IOS8)
    {
        _aboutViewController.preferredContentSize = CGSizeMake(300, 300);
    }
    [self presentViewController:_aboutViewController animated:YES completion:nil];

В AboutViewController.m

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    if(!IS_IOS8)
    {
        self.view.superview.bounds = CGRectMake(0, 0, 300, 300);
    }
}

IS_IOS8

#define IS_IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8)

В iOS 8 вы также можете использовать UIPresentationController, который дает вам больше возможностей настройки.

person pawel_d    schedule 22.09.2014
comment
Спасибо, что поделились простым способом в iOS 8, я просто потратил 2 часа, пытаясь понять, как это сделать, и в официальном документе (сейчас) об этом ничего нет. - person bontoJR; 26.09.2014
comment
Здорово! Помните, что вы также можете определить предпочтительный размер содержимого Interface Builder. - person MrAlek; 07.10.2014
comment
ПредпочитаемыйКонтентСизе отлично работает для меня. Но мне нужно изменить свою позицию в iOS 8. Какое свойство мне нужно использовать? - person Vipin Vijay; 27.01.2015
comment
@VipinVijay Я не тестировал это, но, возможно, вы можете использовать UIPresentationController UIViewControllerTransitioningDelegate. Проверьте мой другой ответ и попробуйте установить frameOfPresentViewInContainerView: stackoverflow.com/questions/25903412/ - person pawel_d; 27.01.2015

У меня была проблема с центрированием модального окна нестандартного размера, пока я не выяснил, что ViewController.view.superview.frame было установлено изначально. Он определяется на основе типа UIModalPresentation. superview.center даже не нужен (насколько показывает мое тестирование).

Кроме того, я установил координаты динамически с помощью [UIScreen mainScreen].applicationFrame, пока поддерживаю только альбомную ориентацию. Вы должны выполнить условную проверку для поддержки портретной и альбомной ориентации, перевернув значения X / Y и высоты / ширины.

Вот мое первое рабочее решение для iOS 6.0:

ViewController.modalPresentationStyle = UIModalPresentationFormSheet;
ViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:ViewController animated:YES completion:nil];
ViewController.view.superview.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
ViewController.view.superview.frame = CGRectMake(
                                                                    // Calcuation based on landscape orientation (width=height) 
                                                                    ([UIScreen mainScreen].applicationFrame.size.height/2)-(320/2),// X
                                                                    ([UIScreen mainScreen].applicationFrame.size.width/2)-(320/2),// Y
                                                                    320,// Width
                                                                    320// Height
                                                                    );

А потом я посмотрел на предыдущий ответ и посмотрел на него ладонью. Немного сокращает мое решение, заменяя последнюю строку на:

ViewController.view.superview.bounds = CGRectMake(0, 0, 320, 320);

РЕДАКТИРОВАТЬ для окончательного решения и замечаний.

person Brenden    schedule 12.11.2012
comment
Обычно я использую то же решение для изменения размера модального представления. Но я понимаю, что это не работает для iOS 6. Представление всегда застревает в верхней части родительского представления. Любое решение ?? Благодарность - person Frade; 03.12.2012
comment
Я тестировал ipad с ios 6 и не видел, чтобы это произошло. Что вы тестируете? Это решение работает, если вы его протестируете? - person Brenden; 11.12.2012
comment
Моя проблема в том, что я не могу изменить происхождение кадра супервизора. он меняет размер, но не центр. только если я сделаю это по завершению блока .. - person Frade; 11.12.2012
comment
Просто предположение, может быть, потому что его контроллер меняет его после того, как вы его изменили, поэтому кажется, что вы не можете его изменить. - person Brenden; 31.12.2012

Лучший способ сделать это - изменить свойство bounds в супервизоре представления, представленного внутри формы. Когда вы представляете представление модально, представленное представление встроено в другое представление.

Вы должны установить свойство bounds супервизора в тот же прямоугольник, что и границы представления. Сначала добавьте частный ivar в свой класс:

@implementation MySpecialFormsheet {
    CGRect _realBounds;
} 

Лучше всего сделать это за viewWillAppear:. Добавьте следующий код к контроллеру представления, который представлен модально:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.view.superview.bounds = _realBounds;
}

Вам необходимо кэшировать _realBounds в своем viewDidLoad методе:

- (void)viewDidLoad {
    _realBounds = self.view.bounds;
    [super viewDidLoad];
}
person Rob Jones    schedule 13.04.2012
comment
Привет, в моем приложении я использовал новый вид слева, а не в центре. Как это сделать? - person Fire Fist; 28.08.2012
comment
Не уверен в более ранних версиях, но с iOS 6.0 представление больше не центрируется. Координата x всегда начинается там, где должна быть обычная форма. Не похоже, чтобы это можно было исправить с помощью self.view.center или self.view.superview.center. - person memmons; 14.01.2013
comment
@Answerbot Я не совсем понимаю, что вы пытаетесь сказать. Этот метод работает у меня на iOS 6. - person Rob Jones; 15.01.2013

даже для уменьшения высоты и ширины формного листа вы можете использовать

[self.view.superview setBounds:CGRectMake(0, 0, 450, 480)];
person Kasaname    schedule 11.10.2012
comment
Боже, я до сих пор не могу поверить, как это просто! Я действительно планировал создать собственное представление для имитации эффекта UIModalViewController. Спасибо! - person DZenBot; 11.07.2013

Это мое решение для просмотра НЕ с автоматическим размещением (никогда не пробовал с автоматическим размещением) и совместимое с iOS 7 и iOS 8.

Сначала обязательно вызовите модальное представление таким образом:

CloudSettingsViewController *cloudController = [[CloudSettingsViewController alloc] initWithNibName:@"CloudSettingsView" bundle:nil];

CGRect originalBounds = cloudController.view.bounds;

cloudController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
cloudController.modalPresentationStyle = UIModalPresentationFormSheet;

[self presentViewController:cloudController animated:YES completion:nil]; 

В iOS 8 установите предпочтительныйContentSize в методе viewDidLoad модального представления.

- (void)viewDidLoad {
    [super viewDidLoad];

    // backup of the original size (selected in interface builder)
    height = self.view.frame.size.height;
    width = self.view.frame.size.width;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) // versioni successive ios 8
        self.preferredContentSize = CGSizeMake(width, height); // this is necessary to get the correct size of the modal view
}

Это работает ТАКЖЕ, когда в модальном представлении должна отображаться клавиатура на iPad.

В предыдущих версиях iOS 8 вы должны установить границы после вызова presentViewController:

[currentController presentViewController:controlPanelController animated:YES completion:nil];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8) 
    cloudController.view.superview.bounds = originalBounds;//it's important to do this after 
person Magurizio    schedule 24.09.2014
comment
ПредпочитаемыйКонтентСизе отлично работает для меня. Но мне нужно изменить свою позицию в iOS 8. Какое свойство мне нужно использовать? - person Vipin Vijay; 27.01.2015
comment
@VipinVijay: Вы придумали, как изменить положение в iOS 8 и выше? - person UditS; 19.07.2016

Подходы, описанные выше, необходимо настроить для iOS7:

// set desired bounds, then call -presentFromViewController:

@implementation PresentedViewController
{
    CGRect _presentationBounds;
}

- (void)presentFromViewController:(UIViewController *)viewController
{
    self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    self.modalPresentationStyle = UIModalPresentationFormSheet;

    _presentationBounds = self.view.bounds;

    [viewController presentViewController:self animated:YES completion:nil];
}

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    if (!CGRectIsEmpty(_presentationBounds))
    {
        self.view.superview.bounds = _presentationBounds;
        _presentationBounds = CGRectZero;
    }
}

(Этот код также работает на iOS6.)

person hatfinch    schedule 05.12.2013

Даже я довольно долго боролся с той же проблемой. Сделав несколько попыток из многих из приведенных здесь ответов, я пришел к решению, которое для меня очень хорошо сработало.

Вот код при представлении контроллера представления.

    SomeViewController *sovcObj = [[SomeViewController alloc] initWithNibName:@"SyncOptionsViewController" bundle:nil];
someObj.modalPresentationStyle = UIModalPresentationFormSheet;
someObj.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:someObj animated:YES completion:nil];
someObj.view.superview.bounds = CGRectMake(0, 0, 400, 400); // whatever width and height you want

В xib (если вы его используете) в разделе «Simulated Metrics» выберите размер «Freeform».

Помимо этого, вам необходимо написать приведенный ниже код в представленном контроллере представления (например, SomeViewController в этом примере)

- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, 400, 400); // whatever width and height you want

}

Этот код также работает для iOS 7.

person Rajesh    schedule 21.01.2014
comment
Хотел бы я проголосовать за это дважды. Я пробовал ВСЕ (около 3 часов своей жизни посвятил исключительно этому), пока это, наконец, не сработало. Спасибо. - person LMVogel; 21.12.2015

Одним из решений является использование UIModalPresentationPageSheet для представления листа страницы с последующим немедленным изменением размера модального представления. Это полностью объясняется в это ответ на другой вопрос.

person Travelling Man    schedule 08.02.2011

Измените размер модального представления "после" его представления с помощью метода presentModalViewController. См. Эту ссылку, чтобы изменить размер модального представления https://coderwall.com/p/vebqaq

person NetDeveloper    schedule 02.05.2013
comment
Отправьте ответ, а не ссылку. - person Rob Jones; 17.06.2013
comment
По сути, сообщение в приведенной выше ссылке предлагает изменить размер модального представления после его представления с использованием метода presentModalViewController. - person NetDeveloper; 27.07.2013

Вы можете использовать MZFormSheetController следующим образом:

MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithSize:customSize viewController:presentedViewController];
[presentingViewController mz_presentFormSheetController:formSheet animated:YES completionHandler:nil];
person Maxim Pavlov    schedule 22.01.2015

Это решение сработало для меня, так как у меня была такая же проблема.

Моя модальная структура представления следующая (я использую UIModalPresentationCurrentContext как при представлении, так и при представлении контроллеров для достижения прозрачности в представленной VC)

ModalViewController
  > UIView (view) - resized to the same size as the presenting controller but has semi-translucent background - done automatically
      >> UIView (contentView) - the true view with the content of the popup - this is the one that got consistently placed at the top of the screen all the time

В ModalViewController я перезаписал следующий метод, чтобы исправить проблему с позиционированием:

- (void) viewWillLayoutSubviews(){
  [super viewWillLayoutSubviews];

  CGRect r = self.view.bounds();
  self.contentView.center = CGPointMake(r.size.width/2,r.size.height/2);
}

На самом деле я сначала создаю и изменяю размер представления содержимого, но другим способом.

Надеюсь, это кому-то поможет.

person Moonwalker    schedule 21.01.2015