как я могу использовать одну раскадровку для 4 и 3,5 экранов iphone с авторазметкой (ios6 + ios7)?

Хотя есть много вопросов и ответов о создании макета раскадровки, который будет работать как на 4-дюймовом, так и на 3,5-дюймовом экране, я не смог найти подходящего решения для следующего сценария.

Я использую autolayout с ios6 (и ios7), и мне не нужно поддерживать landscpae или ipad. У меня есть UIView с несколькими подвидами, которые должны выглядеть как макет ниже. В раскадровке легко настроить ограничения автомакета, чтобы они соответствовали любому размеру экрана. Мой вопрос: как заставить автомакет выбирать правильные ограничения в зависимости от размера экрана во время выполнения?

МОКАПЫ ЭКРАНА

Обратите внимание, что я НЕ хочу использовать 2 разные раскадровки. Выполнение этого во всем моем приложении потребовало бы много работы, и мне пришлось бы подключить все делегаты, выходы и действия на каждой раскадровке. Замена экрана потребует от меня двойной работы.

Я пробовал 2 метода, чтобы заставить эту работу работать на одной раскадровке, но я не удовлетворен ни одним из них.

  • Удвойте ограничения. Большее ограничение (50) имеет более высокий приоритет, чем меньшее ограничение (30). Проблема с этим подходом заключается в том, что на экране размером 3,5 дюйма автомакет может выбрать всего несколько ограничений с более низким приоритетом — достаточно, чтобы удовлетворить макет — но оставить некоторые ограничения с высоким приоритетом.

двойные ограничения

  • Подкласс NSLayoutConstraint. В этом методе все ограничения в раскадровке устанавливаются как NSDualLayoutConstraint. В коде инициализации NSDualLayoutConstraint константа ограничения изменяется на значение 3_5_constant в случае, если размер экрана во время выполнения составляет 3,5 дюйма. Этот метод более детерминирован, но вы не можете увидеть макет 3,5 дюйма в предварительном просмотре построителя интерфейса. .

введите здесь описание изображения


Если бы только ограничения построителя интерфейса имели вторичное постоянное значение, которое применялось бы при размере экрана 3,5", это решило бы мою проблему. Итак, я остаюсь со своим вопросом - как я могу правильно использовать одну раскадровку для правильной компоновки ее подвидов для Размеры экрана 4" И 3,5"?


person gardenofwine    schedule 29.10.2013    source источник
comment
Я бы посоветовал вам сделать это программно в таких случаях!   -  person Zalykr    schedule 29.10.2013
comment
@Heliem, для того, чтобы сделать это программно, ему потребуется добавить условия во все свои ViewControllers, чтобы выбрать между 3,5 ''и 4.0 ''. На самом деле нет никакой разницы, кроме всего дополнительного кода.   -  person Indigon    schedule 29.10.2013
comment
@ Индигон не совсем так, я думаю, у него проблемы только в тех случаях, когда ему нужны разные ограничения в зависимости от размера экрана. Если да, то он мог делать только те программно   -  person Zalykr    schedule 29.10.2013
comment
@Heliem, мое второе предлагаемое решение состоит в программном изменении констант; разница в том, что в моем решении значения альтернативных значений устанавливаются в построителе интерфейса как атрибуты времени выполнения, а код «switcharoo» существует только в NSLayoutConstraint То, что вы предлагаете, - это гораздо больше кода (IBOutlet для каждого ограничения в раскадровке), и меньше заметности)   -  person gardenofwine    schedule 29.10.2013
comment
Пробовали ли вы комбинировать ограничения «меньше или равно» и «больше или равно»? Например высота большого внутреннего вида меньше или равна 248 и больше или равна 220.   -  person patric.schenke    schedule 19.11.2013
comment
@ patric.schenke Я пробовал это, но это дает еще менее последовательные результаты, чем метод «двойных ограничений».   -  person gardenofwine    schedule 19.11.2013
comment
Я не могу поверить, что в iOS для этого пока нет подходящего решения. Например, в Android (с момента его выпуска) вы можете указать разные размеры для произвольных размеров экрана в файле xml, и они будут выбраны автоматически. Даже CSS лучше. iOS добавила классы размера, но они не охватывают это. Ваше решение с настраиваемым классом ограничений хорошее, по крайней мере, лучше, чем их программная установка. Вы можете улучшить его, используя @IBDesignable и @IBInspectable, чтобы теперь приходилось возиться с атрибутами времени выполнения.   -  person User    schedule 01.05.2016
comment
@gardenofwine и Ixx, вы можете найти подходящее решение здесь: stackoverflow.com/a/37325714/2477632   -  person HamzaGhazouani    schedule 19.05.2016


Ответы (4)


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

Вам просто нужно будет определить, работает ли пользователь на 4-дюймовом устройстве, и соответствующим образом расположить свои представления.

#define IS_568_SCREEN (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)568) < DBL_EPSILON)

if (IS_568_SCREEN) {
    // Lots of code to layout for 4" devices
} else {
    // Lots of code to layout for 3.5" devices
}

Однако, если бы вы использовали для этого автомакет, вы бы обнаружили, что это сэкономит вам массу времени и кода. Вместо того, чтобы вручную размещать каждое представление в коде, используя решение, о котором я упоминал выше, вам просто нужно обновить ограничения y и высоты в зависимости от устройства.

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

введите здесь описание изображения

#define IS_568_SCREEN (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)568) < DBL_EPSILON)

if (IS_568_SCREEN) {
    self.layoutConstraintY.constant = 50.0f;
    self.layoutConstraintHeight.constant = 248.0f;
} else {
    self.layoutConstraintY.constant = 30.0f;
    self.layoutConstraintHeight.constant = 220.0f;
}
[self layoutIfNeeded];
person Jeremy Fox    schedule 22.01.2014
comment
Мой вопрос действительно касался автомакета, поэтому я комментирую ваше второе предложение, которое заключается в редактировании ограничений с помощью кода. Это предложение, которое я придумал в своем вопросе. См. этот комментарий, который я сделал другому ответчику: stackoverflow.com/questions/19658140/ - person gardenofwine; 22.01.2014
comment
Спасибо за такой подробный ответ - person nicktones; 17.03.2014
comment
Замысловатый танец с fabs() и DBL_EPSILON совершенно не нужен. Я видел, как это скопировано вокруг кучу в контексте проверки размера экрана, и это основано на непонимании проблем с округлением с плавающей запятой. В этом контексте == прекрасно подходит. (Кроме того, вы, вероятно, захотите использовать неравенство, чтобы, если Apple выпустит еще больший экран, он не вернулся к макету 3,5.) - person Paul Cantrell; 12.08.2014

Этот ответ stackoverflow решил для меня ту же проблему.

Ключом является создание IBOutlet для ограничения (например, высоты). Затем сделайте что-то вроде этого

- (void)updateViewConstraints {
    [super updateViewConstraints];

    self.myConstraintFromIB.constant =
        [UIScreen mainScreen].bounds.size.height > 480.0f ? 200 : 100;
}
person carbonr    schedule 28.04.2014
comment
Я уже предложил лучшее решение в своем вопросе (подкласс NSLayoutConstraint - NSDualLayoutConstraint) - person gardenofwine; 29.04.2014
comment
это плохой ответ, хотя это мой собственный. Пожалуйста, лучше поймите свою проблему, и вы сможете решить ее, не выполняя подобную проверку. - person carbonr; 13.08.2014

Вам нужно будет отредактировать ограничения программно. Этот вопрос может оказаться полезным для вас.

Вы также можете иметь два отдельных файла раскадровки или две сцены viewController в одном файле раскадровки.

person WolfLink    schedule 21.11.2013
comment
Мой второй подход к проблеме включает в себя программное изменение ограничений (путем создания подкласса NSLayoutconstraint; и мой вопрос конкретно требует решения с ОДНОЙ раскадровкой. - person gardenofwine; 24.11.2013

Как насчет того, чтобы добавить дополнительный вид и включить в него квадратный вид? Дополнительный вид должен быть прозрачным, чтобы его никто не видел. Установите ограничения дополнительного вида, чтобы они расширялись с размером экрана, и установите ограничения квадратного вида, чтобы они были центрированы в дополнительном поле. Выберите множитель для размера квадратного изображения относительно дополнительного поля.

person Martin Lockett    schedule 21.11.2014
comment
Чем отличается ваше предложение от установки ограничений множителя для самого квадратного представления? - person gardenofwine; 22.11.2014