Как адаптировать приложение под разрешение экрана
На странице фрагмента на официальном сайте приводятся куски кода приложения. Это приложение отображает список заголовков статей и содержимое выбранной статьи, а его вид зависит от ориентации экрана. В горизонтальной ориентации, оно отображает и заголовки и содержимое(два фрагмента в одном Activity). В вертикальной ориентации заголовки и содержимое отображаются на разных экранах (два фрагмента разделены по двум Activity).
Пример достаточно полезен, и я решил, что имеет смысл разобрать его детально. Я немного поменяю и сокращу код, но общий смысл конструкции останется неизменным. Также, думаю, будет полезным, если мы создадим приложение так, что оно будет запускаться на версиях более ранних, чем третья. Ну и в довесок сделаем так, чтобы оно работало адекватно на экранах разных размеров.
Соответственно урок состоит из трех частей.
1. Приложение, отображающее слева заголовки, а справа – содержимое
2. Добавляем учет ориентации. При вертикальной будем отображать заголовки на первом экране, а содержимое на втором.
3. Добавляем учет размера экрана. Для небольших экранов в любой ориентации будем отображать заголовки на первом экране, а содержимое на втором.
Долго думал, как назвать проект. Решил – MultipleScreen.
Project name: P1151_MultipleScreen
Build Target: Android 2.2
Application name: MultipleScreen
Package name: ru.startandroid.develop.p1151multiplescreen
Create Activity: MainActivity
Добавим строки в strings.xml:
Два массива – заголовки и содержимое.
Не забывайте, что мы используем библиотеку v4, чтобы наше приложение с фрагментами работало на старых версиях.
Создаем фрагмент, который будет отображать список заголовков
TitlesFragment.java:
Класс наследует ListFragment для удобства работы со списком.
onItemClickListener – интерфейс, который будет наследовать Activity. Подробно эту схему мы разбирали в Уроке 106. Интерфейс имеет метод itemClick, который фрагмент будет вызывать при выборе элемента списка.
В onCreate создаем адаптер с заголовками и передаем его списку.
В onAttach записываем Activity (к которому присоединен фрагмент) в listener. Разумеется, это Activity должно реализовывать интерфейс onItemClickListener.
В onListItemClick, мы через listener посылаем в Activity данные о выбранном элементе.
Т.е. этот фрагмент покажет нам заголовки и уведомит Activity о том, какой из них был выбран.
Создаем второй фрагмент, для отображения содержимого.
layout-файл details.xml:
TextView, который будет отображать содержимое.
Класс DetailsFragment.java:
Метод newInstance создает экземпляр фрагмента и записывает в его атрибуты число, которое пришло на вход методу. Это число будет содержать позицию выбранного элемента из списка заголовков.
Метод getPosition достает из аргументов позицию.
onCreateView создает View, находим в нем TextView, и помещает в этот TextView содержимое, соответствующее позиции.
Для нас тут новыми являются аргументы фрагмента. Они могут быть заданы строго до того, как фрагмент будет присоединен к какому либо Activity, т.е., обычно, сразу после создания фрагмента. Они хранятся в фрагменте даже после того, как он был пересоздан в результате, например, смены ориентации экрана. Метод setArguments позволяет записать аргументы, а getArguments – считать.
Этот фрагмент при создании читает содержимое по переданной ему позиции и выводит в TextView.
Настраиваем Activity. layout-файл main.xml:
Слева будет TitlesFragment с заголовками, а в правой части будем помещать DetailsFragment в контейнер FrameLayout.
MainActivity.java:
Activity наследует интерфейс onItemClickListener, чтобы получать оповещения о выбранных элементах от фрагмента со списком заголовков. Поле position будет хранить последний выбранный элемент. Это поле сохраняем (onSaveInstanceState) и читаем (savedInstanceState в onCreate) при пересоздании Activity.
В onCreate вызываем метод, который покажет последнюю выбранную запись.
Метод showDetails получает на вход позицию, ищет DetailsFragment. Если не находит или находит но, отображающий данные по другой позиции, то создает фрагмент заново, передает ему нужную позицию и размещает в контейнер.
itemClick – метод, вызываемый из фрагмента со списком заголовков. В нем мы получаем позицию выбранного элемента в списке. Пишем ее в поле position и вызываем showDetails, который отобразит нужные данные на экране.
Все сохраняем, запускаем приложение.
Выберем какой-либо пункт
все работает, как и должно.
Теперь добавим учет ориентации экрана. В вертикальной ориентации MainActivity будет отображать только заголовки. Фрагмент с содержимым вынесем в отдельное DetailsActivity
DetailsActivity.java:
Код из рубрики: «все слова вроде знакомые, а че сказать хотел - непонятно». Давайте разбираться.
Представим ситуацию. Мы поворачиваем планшет вертикально, у нас отобразятся только заголовки. Мы нажимаем на какой-либо заголовок и переходим на DetailsActivity, которое покажет нам содержимое (средствами DetailsFragment, разумеется). Т.е. мы имеем вертикальную ориентацию и видим содержимое. Теперь поворачиваем планшет горизонтально. Что будет? DetailsActivity отобразится во весь горизонтальный экран и покажет содержимое. Но наша концепция гласит, что в горизонтальной ориентации приложение должно показывать и содержимое и заголовки, ширина экрана ведь позволяет это сделать. А, значит, нам надо вернуться в MainActivity.
Смотрим первый фрагмент кода. Приложение определяет, что ориентация горизонтальная и в этом случае просто закрывает Activity. И т.к. это DetailsActivity у нас будет вызвано из MainActivity, то после finish мы попадаем в MainActivity и видим то, что нужно – и заголовки, и содержимое. Причем MainActivity хранит номер выбранного заголовка (независимо от ориентации) и содержимое отобразится то же самое, что было в DetailsActivity.
Смотрим второй фрагмент. Мы проверяем, что savedInstanceState == null – это означает, что Activity создается первый раз, а не пересоздается после смены ориентации экрана. Далее мы создаем фрагмент DetailsFragment, используя позицию из интента, и помещаем его в Activity.
Почему создаем фрагмент только при создании Activity и при пересоздании - нет? Потому что система сама умеет пересоздавать существующие фрагменты при поворотах экрана, сохраняя при этом аргументы фрагмента. И нам совершенно незачем в данном случае пересоздавать фрагмент самим.
Причем тут надо понимать, что система будет создавать фрагмент вовсе не через метод newInstance. Она просто не знает такой метод. Система использует конструктор. И мы ничего не можем передать в этот конструктор, чтобы повлиять на поведение или содержимое фрагмента. Именно в таких случаях выручают аргументы. Система сохраняет аргументы фрагмента при его пересоздании. И при каждом пересоздании наш фрагмент будет знать, какое содержимое он должен отобразить, т.к. использует аргументы при создании экрана в методе onCreateView.
Не забудьте прописать Activity в манифесте.
Создадим папку res/layout-land и скопируем туда основной layout - res/layout/main.xml. Т.е. при горизонтальной ориентации у нас все останется, как есть.
А res/layout/main.xml поменяем следующим образом:
Мы удалили контейнер для содержимого, оставили только заголовки. Такой экран мы получим в вертикальной ориентации.
Меняем MainActivity.java:
Изменений немного. Добавляется поле withDetails, которое будет сообщать нам: показывает Activity заголовки с содержимым или без. В нашем случае это будет совпадать соответственно с горизонтальной и вертикальной ориентацией.
В onCreate мы задаем значение withDetails с помощью проверки наличия контейнера для фрагмента с содержимым. Если у нас должно отображаться содержимое, то вызываем метод showDetails и передаем ему позицию. Если содержимое не должно отображаться, то ничего не делаем, показываем только заголовки.
В методе showDetails мы смотрим withDetails. Если содержимое должно быть показано здесь же, то работает старый алгоритм, мы создаем фрагмент. Если же содержимое должно быть показано в отдельном Activity, то вызываем DetailsActivity и передаем ему позицию.
Все сохраняем, запускаем приложение.
видим только заголовки
видим содержимое в новом Activity
видим содержимое и заголовки
Осталось подстроить работу приложения под маленькие экраны. Напомню, что на мелких экранах мы при любой ориентации будем разделять заголовки и содержимое по разным Activity. Размер экрана можно определять по-разному. Я буду считать большими экраны large и xlarge. Для этих экранов логика остается текущая, для остальных немного изменим.
Ориентация экрана бывает горизонтальная (land) и вертикальная (port). Экраны мы будем различать: мелкие, large и xlarge. Итого у нас получается 6 комбинаций экранов.
И у нас уже есть два варианта файла main.xml – "заголовки с содержимым" и "только заголовки".
Надо сопоставить комбинации и варианты.
Вариант "заголовки с содержимым" будем использовать в комбинациях 5,6 (большие экраны в горизонтальной ориентации)
Вариант "только заголовки" подходит к комбинациям 1,2,3,4 (мелкие экраны в любой ориентации и большие экраны в вертикальной ориентации).
Создаем layout-папки под эти комбинации, и помещаем в них варианты экранов.
Папка res/layout-large-land. Это комбинация 5. Сюда помещаем вариант main.xml, который "заголовки с содержимым".
Папка res/layout-xlarge-land. Это комбинация 6. Сюда помещаем вариант main.xml, который "заголовки с содержимым".
Папка res/layout. Это все остальные комбинации (1,2,3,4). Сюда помещаем вариант main.xml, который "только заголовки".
Т.е. в итоге получается, что мы в папки layout-large-land и layout-xlarge-land копируем файл из layout-land, и удаляем папку layout-land. Папку layout не трогаем, там все ок.
Осталось немного изменить DetailsActivity.java:
Метод isLarge определяет, большой экран или нет. Если раньше мы в горизонтальной ориентации сразу закрывали это Activity, то теперь будем делать это только для больших экранов. А на остальных содержимое будет отображаться в горизонтальной ориентации.
Все сохраняем и запускаем приложение.
Скрины с планшета приводить не буду. Они полностью повторят предыдущие.
А на смартфоне с маленьким экраном будет так:
Жмем назад и попадаем к заголовкам
Немаленький такой материал получился. Но, вроде, все рассказал, чего хотел.
На всякий случай напоминаю, что архитектура решения не моя. Я разбирал пример, который немного поменял. Я перенес логику из фрагмента заголовков в главное Activity и убрал использование режима выбора и выделение элементов списка. Зато добавил работу с квалификаторами, которые позволили нам менять поведение приложения в зависимости от размера и ориентации экрана.
Если остались непонятные моменты – велкам на форум, будем решать.
На следующем уроке:
- меняем поведение Activity в Task
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Android работает на многих разных устройствах, каждый из которых имеет широкий спектр разрешений, размеров экрана и плотности экрана. Android выполнит масштабирование и измените размер, чтобы приложение работало на этих устройствах, но это может привести к неоптимальному взаимодействии с пользователем. Например, изображения могут выглядеть размытыми, или же они могут располагаться как ожидается в представлении.
Основные понятия
Для обеспечения поддержки нескольких экранов важно понимать несколько терминов и концепций.
Размер экрана – Объем физического пространства для отображения приложения
Плотность экрана – Количество пикселей в любой заданной области экрана. Типичная единица измерения — точка на дюйм (DPI).
Решение – Общее количество пикселей на экране. При разработке приложений разрешение не так важно, как размер и плотность экрана.
Независимый от плотности пиксель (DP) – Виртуальная единица измерения, позволяющая разрабатывать макеты независимо от плотности. Эта формула используется для преобразования точки DP в экранные пиксели:
px = DP × dpi ÷ 160
Ориентация страницы – Ориентация экрана считается альбомной, если она шире, чем высота. В отличие от ориентации, книжная ориентация имеет значение, когда высота экрана превышает ширину. Ориентация может измениться в течение времени существования приложения, когда пользователь поворачивает устройство.
Обратите внимание, что первые три из этих концепций являются взаимосвязанными – . Увеличение разрешения не приводит к увеличению размера экрана. Однако при увеличении плотности и разрешения размер экрана может остаться неизменным. Такая связь между размером экрана, плотностью и разрешением усложняет поддержку экрана.
Для решения этой сложности платформа Android предпочитает использовать аппаратно-независимые пиксели (DP) для макетов экрана. Используя независимые от плотности Пиксели, элементы пользовательского интерфейса будут отображаться для одного и того же физического размера на экранах с различной плотностью.
Поддержка различных размеров и плотности экрана
Android обрабатывает большую часть работы, чтобы правильно отобразить макеты для каждой конфигурации экрана. Однако есть некоторые действия, которые можно предпринять, чтобы помочь системе.
Использование независимых от плотности пикселей вместо фактических пикселей в макетах является достаточным в большинстве случаев для обеспечения независимости от плотности. Android будет масштабировать драваблес во время выполнения до соответствующего размера. Однако возможно, что масштабирование приведет к неразмытому появлению растровых изображений. Чтобы обойти эту проблему, предоставьте альтернативные ресурсы для другой плотности. При проектировании устройств для нескольких разрешений и плотности экрана будет проще начать с более высокого разрешения или плотности изображения, а затем уменьшить масштаб.
Объявление поддерживаемого размера экрана
Объявление размера экрана гарантирует, что только поддерживаемые устройства смогут скачать приложение. Это достигается путем установки элемента поддержки-screens в файле AndroidManifest.xml . Этот элемент используется для указания того, какие размеры экрана поддерживаются приложением. Данный экран считается поддерживаемым, если приложение может правильно расположить макеты для заполнения экрана. С помощью этого элемента манифеста приложение не будет отображаться в Google Play для устройств, которые не соответствуют спецификациям экрана. Однако приложение по-прежнему будет работать на устройствах с неподдерживаемыми экранами, но макеты могут выглядеть размытыми и пикселизованным.
Поддерживаемые экранные Сиксес объявляются в файле задающий свойства/AndroidManifest.xml решения:
Измените AndroidManifest.xml , чтобы включить поддержку экранов:
Предоставление альтернативных макетов для различных размеров экрана
Альтернативные макеты позволяют настроить представление для размера экрана спеЦифк, изменяя положение или размер элементов пользовательского интерфейса компонента.
Начиная с уровня API 13 (Android 3,2), размеры экранов не рекомендуются в пользу использования квалификатора SW N DP. Этот новый квалификатор объявляет объем пространства, необходимого для данного макета. Рекомендуется, чтобы приложения, предназначенные для работы на Android 3,2 или более поздней версии, использовали эти более новые квалификаторы.
Например, если для макета требуется минимальная 700-я точка в ширину экрана, альтернативный макет будет находиться в макете папки — sw700dp:
Ниже приведены некоторые значения для различных устройств.
Обычный телефон – 320 DP: обычный телефон
Устройство с 5 "планшетом/" или "tween-анимацией" – 480 DP: например, Примечание Samsung
7 "планшетный – 600 DP: например, Барнса & благородные Нук
10 "Планшет – 720 DP: например, Ксум Motorola
Для приложений, предназначенных для уровней API до 12 (Android 3,1), макеты должны находиться в каталогах, использующих квалификаторы малого / обычного / размера / ксларже , как обобщения различных размеров экрана, доступных на большинстве устройств. Например, на рисунке ниже приведены дополнительные ресурсы для четырех различных размеров экрана:
Ниже приведено сравнение того, как более старые квалификаторы размера экрана, предшествующие API уровня 13, сравниваются с пикселями, не зависящими от плотности.
426 DP x 320 DP невелика
470 DP x 320 DP является нормальной
640 DP x 480 DP большие
960 DP x 720 DP — ксларже
Новые квалификаторы размера экрана на уровне API 13 и выше имеют более высокий приоритет, чем предыдущие квалификаторы экрана на уровнях API 12 и ниже. Для приложений, которые будут охватывать старый и новый уровни API, может потребоваться создать альтернативные ресурсы с помощью обоих наборов квалификаторов, как показано на следующем снимке экрана:
Укажите разные точечные рисунки для различной плотности экрана
Несмотря на то, что Android будет масштабировать точечные рисунки по мере необходимости для устройства, растровые изображения могут не элегантной масштабирование. они могут стать нечеткими или размытыми. Предоставление точечных рисунков, подходящих для плотности экрана, снизит эту проблему.
Например, приведенный ниже рисунок представляет собой пример проблем макета и внешнего вида, которые могут возникнуть, если не предоставлены ресурсы с указанием плотности.
Сравните это с макетом, который предназначен для ресурсов, зависящих от плотности:
Создание ресурсов с различной плотностью с помощью Android Asset Studio
Создание этих растровых изображений различной плотности может быть немного утомительным. Таким образом, Google создал интерактивную служебную программу, которая может сократить некоторые долгой, связанные с созданием этих точечных рисунков под названием Android Asset Studio.
Этот веб-сайт поможет при создании точечных рисунков, нацеленных на четыре распространенные плотности экрана, путем предоставления одного изображения. После этого Android Asset Studio создаст точечные рисунки с некоторыми настройками, а затем позволит скачать их в виде ZIP-файла.
Советы для нескольких экранов
Android работает на ошеломляющей количестве устройств, и сочетание размеров экрана и плотности экрана может показаться огромным. Приведенные ниже советы помогут сократить усилия, необходимые для поддержки различных устройств.
Разработка и разработка только для того, что вам нужно – Существует множество различных устройств, но некоторые из них существуют в редких конструктивных факторах, которые могут требовать значительных усилий при проектировании и разработке. Панель мониторинга " размер и плотность экрана " — это страница, предоставляемая Google, которая предоставляет данные о декомпозиции размера экрана и матрицы плотности экрана. Эта декомпозиция позволяет получить представление о том, как выполнять разработку на экранах с поддержкой.
Использование DP, а не пикселей в пикселях, становится проблематичным при изменении плотности экрана. Не жестко кодировать значения пикселей. Старайтесь не использовать пикселов в качестве точки распространения (не зависящих от плотности).
Избегайте абсолутелайаут везде, где это возможно – , не рекомендуется на уровне API 3 (Android 1,5) и приведет к нестабильнымм макетов. Его не следует использовать. Вместо этого попробуйте использовать более гибкие графические элементы макета, такие как элемент LinearLayout, RelativeLayoutили новое значение GridLayout.
Выбрать одну ориентацию макета по умолчанию – Например, вместо использования альтернативных ресурсов Layout-Land и Layout-Port, разместите ресурсы для альбомной ориентации в макете, а ресурсы для книжной ориентации — на порт макета.
Использовать лайаутпарамс для высоты и ширины . при определении элементов пользовательского интерфейса в XML-файле макета приложение Android, использующее значения wrap_content и fill_parent , будет иметь более успешный вид на различных устройствах, чем использование пикселей или единиц распределения плотности. Эти значения измерений приводят к тому, что Android масштабирует ресурсы растрового изображения соответствующим образом. По той же причине единицы, не зависящие от плотности, лучше зарезервированы для при указании полей и дополнений элементов пользовательского интерфейса.
Тестирование нескольких экранов
Приложение Android должно быть протестировано для всех конфигураций, которые будут поддерживаться. Оптимальные устройства следует тестировать на самих устройствах, но во многих случаях это невозможно или практично. В этом случае будет полезно использовать программу установки эмулятора и виртуальных устройств Android для каждой конфигурации устройства.
Пакет SDK для Android предоставляет некоторые обложки эмулятора, которые могут использоваться для создания AVD, которые будут реплицировать размер, плотность и разрешение множества устройств. Многие поставщики оборудования также предоставляют обложки для своих устройств.
Другой вариант — использовать службы службы тестирования третьих сторон. Эти службы будут принимать APK, запускать их на различных устройствах, а затем оставлять отзывы о том, как работает приложение.
Вопросы адаптивности приложения или игры под различные размеры экранов это пожалуй одно из самых нелёгких задач в Web-девелопинге. Причиной этому являются разнообразные физические размеры экрана, PPI (Количество пикселей на дюйм), а также собственно разрешение в пикселях. При разработки приложения или игры на HTML для мобильных устройств - адаптивность превращается в сущий ад, поскольку там самоё пёстрое разнообразие экраном со своими свойствами.
Мы рассмотрим технологии и способы их реализаций для того чтобы добиться адаптивности, рассмотрим пути по которым следует двигаться и пути про которые можно забыть.
Сразу замечу очень важный тезис: начинайте делать интерфейс для мобильного экрана и уж только потом представляйте как его пользовать на планшете. С маленького в большой можно в любой момент увеличить scale'ом сохраняя размеры элементов относительно друг друга. Да, будут приятные большие элементы управления это хорошо на самом деле. Намного хуже, когда приходиться делать из большого в маленькое. Вот тут-то и может взорваться голова. Просто всё уменьших как с предыдущим случаем уже не получиться ибо элементы интерфейса на маленьких (физические размеры) экранах будут крошечными.
Немного теории
Давайте немного определимся что такое пиксели под которые мы собираемся делать адаптивный интерфейс. Для начала стоит упомянуть о плотности пикселей.
Коэффициент плотности может быть получен и использован так:
JS: window.devicePixelRatio
CSS: <link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="/hdpi.css" />
Если число равно 1 - значит экран обычной плотности пикселей, 0.75 - низкой, 1.5 - повышенной, 2 - Retina.
Плотность пикселей как вы уже наверное догадались это количество пикселей на единицу физического расстояния. Измеряют в PPI, о котором речь шла ранее. PPI это Pixels per inch (Количество пикселей на дюйм).
Чтобы было понятней CSS-пиксели это не физические пиксели устройства, это абстрактные пиксели. Они нужны для того чтобы экран сам решал как ему нужно их отображать. Например так как Retina экраны имеют высокую плотность и коэффициент 2, то DIV 200x300 CSS пикселей будет располагаться на экране iPhone 4 как 400x600 физических пикселей.
Грубо говоря если у вас ширина экрана 480 пикселей (Как в инструкции написано), это ещё не значит что CSS будет думать что ваша ширина экрана 480 пикселей. Вовсе нет!
Итак, как же определить CSS ширину?
На IOS очень просто это сделать, достаточно вызвать Javascript'ом screen.width и это вернёт как раз CSS размеры, а не фактическое количество пикселей в ширине устройства.
На Android-устройствах к сожалению screen.width возвращает полную ширину экрана без PPI изменений. Поэтому приходиться пользовать другими способами.
Также можно применить странице:
<meta name="viewport" content="width=device-width">
А затем вызвать document.documentElement.clientWidth и в большинстве браузеров это будет CSS шириной.
Если вы разрабатываете игру на андроидовском webview и хотите чтобы содержимое страницы автоматически растягивалось на весь экран - применяйте:
Из минусов появится зум по двойному тапу, поэтому вам нужно будет также убрать его если он не нужен.
Как вы сами наверное догадались сам мета viewport устанавливает браузеру количество CSS пикселей по высоте и ширине. Можно ширине установить 320px и будет 320px, даже если количество пикселей по ширине у вашего устройства 1080. Но будет 320 по ширине и если посчитать, то 1 CSS пиксель в данном случае будет порядка 3x3 физических пикселей устройства. С таким подходом будет здорово делать элементы интерфейса, но вот только дело дойдёт до картинок и вы поймёте что нужно использовать фулл сайз физических пикселей устройства, иначе будет немного низкого качества результат.
Для устройств на OS Android и Windows Phone CSS ширину можно найти поделив значение что вернёт screen.width на devicePixelRatio.
На IOS умножение devicePixelRatio на screen.width будет равно количеству физических пикселей в ширине экрана.
Рекомендую проверить экран таким тестом.
Однако знайте что у разных браузеров значения devicePixelRatio могут быть разными на одном экране. Например взять Galaxy Nexus (720x1280), где команда WebKit дала устройству devicePixelRatio равный 2 (720/360), а выходцы из Опера определили его как 2.25 (720/320).
Если вы хотите знать какие JS вызовы длинны и ширины в каких устройствах и браузерах работают, тогда посетите эту страницу .
В этой теоретической части стоит также вам напомнить о том что существуют "иконные шрифты", которые лучше использовать при построении элементов навигации, не применяя изображения.
Классическая адаптивность
Итак, давайте рассмотрим с помощью чего и как можно добиться адаптивности интерфейса HTML приложения или игры. Возможно всё что ниже будет написано может немного превратиться в кашу, однако я постараюсь сгруппировать по максимуму всё.
1. Просто использовать CSS Медиа запросы
О CSS Media запросах мы уже писали статью, и вот основываясь на использование этих запросов можно сделать адаптивность.
Адаптивность вряд ли получиться хорошей, не для всего. Если у вас страница с контентом, с рассказом о том как Вася провёл лето - это будет нормал, но если у вас ИГРА на HTML+CSS+JS, то тут уже придётся попотеть. Однако игры делаются обычно в canvas или svg, там у них свой собственный scale, который можно крутить и всё общий размер будет меняться сохраняя при этом относительные размер элементов, но об этом дальше.
Если вы хотите именно с помощью медиа запросов делать оформление приложению для мобильных устройств, то вам потребудется таблица размеров вьюпорта , для того чтобы знать под какие разрешения делать медиа запросы. Грубо говоря ширина портретного вьюпорта обычно 320, 360, 384, 400, 480, 496, 533, 540, 600, 640, 648, 758, 768, 800, 1024.
Не забывайте что вы можете не только использовать пиксели, проценты в позиционировании, но также миллиметры (mm), сантиметры (cm) и дюймы (in). Очень часто это может помочь.
Использование Flexible CSS
Для построения адаптивности, также отлично может подойти использование Flexbox CSS, с помощью которого средствами CSS3 можно настроить поведение элементов относительно свойств других элементов. Рекомендуем погуглить Flexbox CSS, если вы не знаете что это такое.
Масштабное увеличение/уменьшение
Здесь я вам поведаю несколько способов адаптирования, при которых на всех экранах все элементы будут располагаться одинаково относительно друг друга, только их размер будет меняться в зависимости от размера экрана.
Используя такую адаптивность, вам следует делать игру/приложения сперва под телефонные экраны и затем масштабировать под планшеты, в противном случае на телефонном экране могут получиться миниатюрные элементы управления.
Использовать SVG
Если ваша игра простая, то вы можете использовать SVG для её отображения. Несмотря на то что на Андроид не поддерживается анимация SVG, адаптивность остаётся адаптивностью, а анимационные трюки можно выполнить и в CSS. Для адаптивности просто указывайте ширину/высоту (Можно высчитать javascript'том) и выставьте атрибут viewBox=”0 0 400 400″, где эти четыре числа замените на свои.
Использовать Canvas
Несмотря на тот факт что производительность Canvas'а уменьшается с ростом разрешения экрана устройства, игроделы используют его для создания игр.
В Canvas'е также можно увеличивать и уменьшать игровое поле в зависимости от размера устройства, но его нужно будет считать самим и адаптировать под канвас. Применять следует методом:
Меняя цифры где 1,1 вы можете менять размер содержимого вьюпорта.
CSS+JS трюки
1. Сперва начнём с одного приёма на JS+CSS, при котором добывается масштабная адаптивность. Суть в том что при любом размере экрана размеры элементов относительно друг друга меняться не будут и всё будет растянуто как надо.
Буквально в нескольких словах опишу действие свойства. Данное CSS свойство способно увеличивать и уменьшать HTML элементы. При уменьшении и увеличении сохраняется центр объекта (т.е. он не смещается как если бы вы уменьшали высоту и ширину) и все вложенные в элемент дочерние HTML элементы также подвергнуться масштабированию.
Как вы уже поняли в scale(x,y), вместо x и y вы ставите число во сколько раз вы уменьшаете/увеличиваете содержимое элемента. Например scale(2,1) означает что вы растяните объект по x-оси и не будете масштабировать по y-оси. Если вы хотите изменять размеры объекта не меняя пропорций, вы можете использовать лишь одно число. Например, scale(3).
Это всё увеличение объектов с помощью свойства scale(). Если же вы хотите уменьшить объект, тогда ставите значения меньше единицы. Например, scale(0.5). Можно также инвертировать оси и для этого в свойстве нужно использовать отрицательные числа.
Плюсом такого масштабирования является прежде всего сохранение размеров дочерних объектов (относительно друг друга) элемента к которому применено свойство.
Адаптивный шрифт
Мало кто знает, но помимо использования классических CSS Media Queries, шрифт может автоматически масштабироваться несколькими путями:
1. Использование единицы измерения vw, vh, vmin, vmax. Например:
Очень немногие знают о том что такое существует в CSS и довольно большое количество браузеров это поддерживают (на некоторых браузерах просто нет поддержки real-time изменения когда вы меняете размер страницы, но оно и не нужно).
Единица измерения vw полностью зависит от ширины браузера (физической ширины), а соответственно также от ширины элемента куда помещён. И установив значения единожды, вы можете быть уверены, что ваш текст будет также отображаться в относительном плане к ширине любого экрана.
Для того чтобы вы лучше понимали что это. 1 vw=1% физической ширины браузера.
Тоже самое можно сказать о vh, только это затрагивает высоты вьюпорта, а не ширину. Отсюда и пошло название vw (View Width) vh (View Height). Соответственно 1 vh= 1% высоты браузера.
1 vmin - 1vw или 1vh (Выбирается тот который физически меньше)
1 vmax - 1vw или 1vh (Выбирается тот который физически больше)
2. Очень полезно иногда использовать для шрифта mm и cm. Таким образом вы не зависите ни от разрешения экрана ни от плотности пикселей и можете спокойно быть уверенными что ваш текст отобразиться примерно одинакового размера на всех типах устройств. Не забывайте об этом!
3. Можно использовать проценты для шрифта (%). Но тут есть один небольшой ньюанс. 100% не значит растянуть шрифт на 100% ширины, высоты или что-то в этом духе. 100% означает использовать точный размер родительского размера шрифта. Что бы понять это масло масляное покажу пример:
Из примера выйдет что к тексту с классом footer примениться размер равный 8px, а к upblock - 24px.
Плюс данного подхода в том что вы можете изменять в зависимости от размера экрана/плотности пикселей только одну величину - родительский размер шрифта, сохраняя при этом размеры шрифта элементов относительно друг друга.
По такому же принципу работает и единица измерения em. Выделяться под неё отдельный пункт не будет поскольку принцип работы тот же самый.
Что вам ещё стоит запомнить из этого пункта, так это то что вы можете задавать родительский размер шрифта также в процентах или в em при чём тогда, 1em = 16px = 100%.
Есть также rem - единица измерения шрифта. Отличается от em тем что наследуется не от родительского элемента, а от того размера шрифта который был указан в html<>.
Не забывайте что вы также можете воздействовать на размер шрифта применяя к целому блоку -webkit-transform: scale(x,y), о котором подробнее говорило выше на странице.
Если вы хотите выровнять по центру какой-то элемент, но у вас никак не получается это задуманным образом сделать, почитайте эту статью.
Если вы знаете чем дополнить материал, обязательно пишите свои мысли в комментарии и прикладывайте рабочий пример в JSFiddle.
Как iOS приложения адаптируются к разным размерам экрана iPhone 12
За последние несколько лет я написал несколько статей, показывающих, как приложения iOS, созданные с использованием разных версий Xcode, будут отображаться при запуске на устройствах с iOS, которые еще не существовали на момент создания приложений. Как правило, приложения следует создавать, используя последнюю версию Xcode, чтобы была возможность использовать предпросмотр для разрешений экрана всех устройств, включая самые новые. Старые приложения запускаются на новых устройствах, но выглядят ужасно. Иногда некоторые элементы приложения выходят за пределы экрана, или приложения выглядят как вытянутые в столбик и/или масштабированные версии этих же приложений для более старых устройств. Опыт, описанный в тех статьях, доказывает, что старые приложения никогда корректно не запускаются с теми разрешениями экрана, которых не существовало при их создании.
На WWDC 2019: 224 Modernizing Your UI for iOS 13 спикер, рассказывая о новых особенностях совместимости приложений, заявил:
“Раньше, если мы создавали новые устройства с новыми разрешениями экрана, ваши приложения отображались некорректно. Что ж, мы изменили это. Таким образом, если ваше приложение создано с использованием iOS 13 SDK, оно всегда будет отображаться с правильным полным разрешением экрана.”
В тот момент я думал, это означает, что мне никогда больше не придется писать статьи по этой теме. Новые iPhone 12 отображают приложения с разным разрешением в зависимости от того, с какой версией Xcode они были созданы. Отменила ли Apple это решение или это относится только к новым разрешениям iPad?
На мероприятии в октябре 2020 года Apple анонсировала четыре новые модели iPhone 12: iPhone 12 mini, iPhone 12, iPhone 12 Pro и iPhone 12 Pro Max. iPhone 12 и 12 Pro имеют одинаковое разрешение экрана и ведут себя идентично. Получается, что при разработке приложений нужно учитывать только три разрешения экрана.
iPhone 12 mini 5.4" with 1080×2340 pixels
iPhone 12 / 12 Pro 6.1" with 1170×2532 pixels
iPhone 12 Pro Max 6.7" with 1284×2778 pixels
Ни одно из этих разрешений не соответствует существующим разрешениям устройств. У iPhone 12 mini есть еще один сюрприз. Как и в случае с iPhone 6+, 6S +, 7+ и 8+, приложение, работающее на iPhone 12 mini, выполняет рендеринг с разрешением, отличным от того, что на самом деле будет отображается на экране.
Прежде чем изучать особенности новых устройств, стоит еще раз взглянуть на поведение некоторых из существующих. Я думаю, что iPhone SE второго поколения, 11 Pro и 11 Pro Max являются наиболее подходящими моделями для сравнения с новыми моделями. В отличие от предыдущих статей этой серии, я также рассматриваю Display Zoom (для усложнения своей задачи и увеличения времени на создание всех этих снимков экрана!)
iPhone SE второго поколения
IPhone SE второго поколения имеет такие же размеры как iPhone 6, 6s, 7 and 8. Следовательно, и ведет он себя точно так же.
Стандартное разрешение
iPhone SE второго поколения имеет разрешение 375 × 667 поинтов.
Xcode 12.1 build of Adaptivity on 2nd generation iPhone SE running iOS 14.1 in portrait
Xcode 12.1 build of Adaptivity on 2nd generation iPhone SE running iOS 14.1 in landscape
Display Zoom
При включенном Display Zoom, iPhone SE второго поколения показывает увеличенное разрешение iPhone SE первого поколения - 320 × 568 поинтов. Такое же разрешение, как у iPhone 5 и 5S. Однако обратите внимание, что высота панели навигации составляет 112 поинтов, что на 1 поинт больше, чем у реального iPhone SE.
Xcode 12.1 build of Adaptivity on 2nd generation iPhone SE running iOS 14.1 in portrait with Display Zoom
Xcode 12.1 build of Adaptivity on 2nd generation iPhone SE running iOS 14.1 in landscape with Display Zoom
iPhone 11 Pro
iPhone 11 Pro имеет такие же размеры и ведет себя так же, как iPhone X и XS.
Стандартное разрешение
iPhone 11 Pro имеет исходное разрешение 375 × 812 поинтов.
Xcode 12.1 build of Adaptivity on iPhone 11 Pro running iOS 14.1 in portrait
Xcode 12.1 build of Adaptivity on iPhone 11 Pro running iOS 14.1 in landscape
Display Zoom
При включенном Display Zoom, iPhone 11 Pro показывает увеличенное разрешение 320 × 693 поинта, если приложение создано с помощью Xcode 12.0 или новее. Это не соответствует ни одному предыдущему устройству. Обратите внимание, что верхняя и нижняя панели немного меньше в поинтах, чем при стандартном масштабировании.
Xcode 12.0 build of Adaptivity on iPhone 11 Pro running iOS 14.1 in portrait with Display Zoom
Xcode 12.0 build of Adaptivity on iPhone 11 Pro running iOS 14.1 in landscape with Display Zoom
iPhone 11 Pro не поддерживает Display Zoom на iOS 13. При сборке с Xcode 11 (т. е. связанным с iOS 13) iPhone 11 Pro с использованием Display Zoom показывает увеличенное, некорректное изображение с разрешением iPhone SE первого поколения (320 × 568 поинтов). Это доказывает, что приложение не видит разрешение экрана, несуществующее в iOS 13. Приложение считает, что статус бар имеет высоту 20 поинтов (как на реальном iPhone SE первого поколения), но iOS продолжает выводить время и другие параметры на самый верх экрана.
Xcode 11.7 build of Adaptivity on iPhone 11 Pro running iOS 14.1 in portrait with Display Zoom
Xcode 11.7 build of Adaptivity on iPhone 11 Pro running iOS 14.1 in landscape with Display Zoom
iPhone 11 Pro Max
iPhone 11 Pro Max имеет тот же размер и поведение, как и iPhone XS Max. IPhone 11 и XR имеют немного другой физический размер и плотность пикселей 2x вместо 3x, но имеют такое же разрешение в поинтах и могут считаться функционально эквивалентными iPhone 11 Pro Max.
Стандартное разрешение
iPhone 11 Pro Max имеет исходное разрешение 414 × 896 поинтов. Высота “моноброви” такая же, как на iPhone 11 Pro.
Xcode 12.1 build of Adaptivity on iPhone 11 Pro Max running iOS 14.1 in portrait
Xcode 12.1 build of Adaptivity on iPhone 11 Pro Max running iOS 14.1 in landscape
Display Zoom
При включенном Display Zoom, iPhone 11 Pro Max показывает увеличенное разрешение iPhone 11 Pro, равное 375 × 812 поинтам. В отличие от iPhone 11 Pro, iPhone 11 Pro Max действительно поддерживает Display Zoom в iOS 13. Приложения, созданные в Xcode 11, будут иметь такое же разрешение на iPhone 11 Pro, что и приложения, созданные в Xcode 12. Опять же, верхняя и нижняя панели немного отличаются по размеру от реального iPhone 11 Pro. Статус бар на 4 поинта короче, а нижняя панель на 3 поинта короче, что дает на 7 поинтов больше вертикальной области для содержимого, чем на iPhone 11 Pro.
Xcode 12.1 build of Adaptivity on iPhone 11 Pro Max running iOS 14.1 in portrait with Display Zoom
Xcode 12.1 build of Adaptivity on iPhone 11 Pro Max running iOS 14.1 in landscape with Display Zoom
iPhone 12 mini
Стандартное разрешение
Экран 1080 × 2340 пикселей предполагает новое разрешение 360 × 780 поинтов, но iPhone 12 mini фактически выдает уменьшенное разрешение iPhone 11 Pro, равное 375 × 812 поинтам. Это означает, что iPhone 12 mini не вводит в разработку приложений новое разрешение. Однако, поскольку реальное физическое количество пикселей не кратно разрешению в поинтах, не получится избежать некоторых артефактов масштабирования. Надеюсь, с 3x экраном они будут незаметны. Статус бар на 6 поинтов выше, чем у iPhone 11 Pro. Нижняя строка имеет такую же высоту.
Xcode 12.1 build of Adaptivity on iPhone 12 mini running iOS 14.1 in portrait
Xcode 12.1 build of Adaptivity on iPhone 12 mini running iOS 14.1 in landscape
Display Zoom
Поскольку iPhone 12 mini ведет себя так же, как и iPhone 11 Pro, то при включенном Display Zoom iPhone 12 mini показывает увеличенное разрешение 320 × 693 поинтов, если приложение создано с использованием Xcode 12.0 и новее. Статус бар на 5 поинтов выше, чем у iPhone 11 Pro с включенным Display Zoom. Нижняя панель имеет такую же высоту.
Xcode 12.0 build of Adaptivity on iPhone 12 mini running iOS 14.1 in portrait with Display Zoom
Xcode 12.0 build of Adaptivity on iPhone 12 mini running iOS 14.1 in landscape with Display Zoom
При сборке с использованием Xcode 11 iPhone 12 mini с включенным Display Zoom выдает увеличенное изображение, такое же, как на iPhone SE первого поколения с разрешением 320 × 568 поинта. iPhone 11 Pro с включенным Display Zoom выдает такое же разрешение.
Xcode 11.7 build of Adaptivity on iPhone 12 mini running iOS 14.1 in portrait with Display Zoom
Xcode 11.7 build of Adaptivity on iPhone 12 mini running iOS 14.1 in landscape with Display Zoom
iPhone 12 / 12 Pro
Стандартное разрешение
В отличие от iPhone 12 mini, iPhone 12 и 12 Pro имеют совершенно новое исходное разрешение - 390 × 844 поинта. Поскольку данное разрешение не встречалось ранее на других устройствах, для возможности использовать предпросмотр в этом разрешении, приложения следует создавать с использованием Xcode 12.1 или новее. Обратите внимание, что в альбомной ориентации горизонтальные размеры меньше (так же, как у iPhone 11 Pro и устройств меньшего размера). Статус бар больше на 3 поинта в сравнении с iPhone 11 Pro. Нижняя панель не изменилась.
Xcode 12.1 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in portrait
Xcode 12.1 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in landscape
Приложения, созданные в Xcode 12.0 и новее, при запуске предпросмотра iPhone 12 или 12 Pro с исходным разрешением, будут использовать увеличенное до 375 × 812 поинтов разрешение iPhone 11 Pro. На этот раз верхняя и нижняя панель такой же высоты, как на настоящем iPhone 11 Pro!
Xcode 12.0 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in portrait
Xcode 12.0 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in landscape
Display Zoom
При включенном Display Zoom, iPhone 12 и 12 Pro выдают увеличенное разрешение 320 × 693 поинта, если приложение создано в Xcode 12.0 или новее. Это то же разрешение, что и у iPhone 11 Pro и iPhone 12 mini с включенным Display Zoom. Верхняя панель на 1 поинт выше, чем у эквивалентного iPhone 11 Pro с включенным Display Zoom, а нижняя панель на 1 поинт ниже.
Xcode 12.0 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in portrait with Display Zooom
Xcode 12.0 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in landscape with Display Zooom
При создании приложения в Xcode 11 iPhone 12 и 12 Pro с включенным Display Zoom выдают такое же увеличенное изображение, что и iPhone SE первого поколения с разрешением 320 × 568 поинта. Такое же разрешение выдают iPhone 11 Pro и iPhone 12 mini при включенном Display Zoom.
Xcode 11.7 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in portrait with Display Zoom
Xcode 11.7 build of Adaptivity on iPhone 12 Pro running iOS 14.1 in landscape with Display Zooom
iPhone 12 Pro Max
Стандартное разрешение
Xcode 12.1 build of Adaptivity on iPhone 12 Pro Max running iOS 14.1 in portrait
Обратите внимание, что в альбомной ориентации размеры по горизонтали стандартные (такие же, как и у меньшего iPhone 11 Pro Max).
Xcode 12.1 build of Adaptivity on iPhone 12 Pro Max running iOS 14.1 in landscape
Приложения, созданные в Xcode 12.0 или в более ранней версии, будут выдавать увеличенное до 414 × 896 поинтов стандартное разрешение iPhone 11 Pro Max. Панели такой же высоты, как и на iPhone 11 Pro Max.
Xcode 12.0 build of Adaptivity on iPhone 12 Pro Max running iOS 14.1 in portrait
Xcode 12.0 build of Adaptivity on iPhone 12 Pro Max running iOS 14.1 in landscape
Display Zoom
При включенном Display Zoom iPhone 12 Pro Max выдает увеличенное разрешение iPhone 11 Pro, равное 375 × 812 поинтам. Статус бар на 3 поинта короче, а нижняя панель на 4 поинта короче, что дает на 7 поинтов больше вертикальной области для содержимого, чем на iPhone 11 Pro.
Xcode 12.1 build of Adaptivity on iPhone 12 Pro Max running iOS 14.1 in portrait with Display Zoom
Xcode 12.1 build of Adaptivity on iPhone 12 Pro Max running iOS 14.1 in landscape with Display Zoom
Вывод
У Apple много опыта в обеспечении обратной совместимости с существующими приложениями при выпуске новых устройств или версий iOS. Линейка iPhone 12 не является исключением (кроме iPhone 12 mini, который всегда имеет разрешение iPhone 11 Pro, масштабируемое по размеру экрана). Высота панелей при масштабировании не всегда соответствует реальному физическому устройству, поэтому обратная совместимость срабатывает не на все 100%. Чтобы иметь возможность использовать новые разрешения iPhone 12/12 Pro и 12 Pro Max в предпросмотре, приложения должны быть созданы с использованием Xcode 12.1.
Display Zoom обычно выдает увеличенную версию меньшего разрешения существующего устройства. Исключениями являются iPhone X, XS и 11 Pro, которые не поддерживали масштабирование дисплея до iOS 14. Они выдают новое разрешение 320 × 693 поинта при использовании Xcode 12 (т.е. по сравнению с iOS 14) и разрешение 320 × 568 поинта при использовании Xcode 11.
Как я запускал приложения Xcode 11 / iOS 13 на симуляторах iOS 14.1?
Вам может быть интересно, как мне удалось сделать снимки экрана с симуляторов Xcode 12.1 / iOS 14.1 с приложениями, созданными с помощью Xcode 11. В моей предыдущей статье iPad Navigation Bar and Toolbar Height Changes в iOS 12 этот процесс объясняется в разделе «Подождите, что вы сказали?».
Adaptivity
Скриншоты в этой статье были взяты из приложения Adaptivity. Adaptivity - это инструмент для разработчиков и дизайнеров, позволяющий визуализировать различные размеры экрана, поля макета, высоту полей и размеры динамического типа, которые современное адаптивное приложение iOS использует при работе на разных устройствах и в многозадачных размерах iPad. Есть также инструменты для просмотра системных цветов, системных изображений и системных материалов, а также инструменты для изучения взаимодействий Pointer Interactions iPadOS 13.4.
Это универсальное приложение является хорошей покупкой и включает в себя версию Mac Catalyst.
Читайте также: