Дисклеймер от редактора: все нижесказанное не относится к разработке игр, создателям которых действительно порой приходится держать в тестовой лаборатории по 3-4 сотни устройств. О разработке игр под Android мы планируем написать отдельно.
Одним из важных отличий планшета Nexus 7 стал великолепный экран. Его разрешение составляет 800х1280 при диагонали 7 дюймов, в то время как «традиционное» разрешение 7-дюймовых планшетов — 600х1024. Теоретически большее разрешение означает то, что приложения будут лучше выглядеть, но, с другой стороны, это еще одно разрешение, под которое разработчикам надо адаптировать свои творения. Масла в огонь подлила портретная ориентация («телефонность») UI Android на новом планшете. Все напряглись, набрали в себя воздух и… «A-a-a-a-and-d-d-dr-r-r-r-ro-o-o-o-oid fr-r-r-r-ragmenta-a-a-a-ation!!!».
Вскоре после выхода Nexus 7 на Google+ (где обычно появляются посты от инженеров «Гугла») появился... пост от инженера «Гугла», руководителя группы по работе над фреймворком Android Дайэн Хэкборн (Dianne Hackborn), известной разработчикам под Android под ником hackbod.
В посте Дайэн рассказала об особенностях экрана Nexus 7, его сходствах с экранами традиционных 7-дюймовых планшетов и отличиях от них. Но сделала она это с использованием непонятных для многих технических терминов, да еще и запутала некоторых разработчиков просьбой не писать адаптированные под экран Nexus 7 версии программ. Откуда-то взялось какое-то непонятное разрешение 600х961 (при чем тут это, разрешение же вроде 800х1280?), появилась новая плотность экрана tvdpi (dpi вроде понятно, но телевизор тут при чем?). В общем, попробуем распутать самостоятельно, ведь от известной своей резкостью дамы этого едва ли дождешься.
В отличие от конкурирующих ОС, Android не накладывает ограничений на размер и разрешение устройств, на которых он может работать. Напомним, что изначально такое ограничение было: в младенчестве (1.5 Cupcake на HTC G1) Android поддерживал только одно разрешение — HVGA (320x480) на 3,5-дюймовом экране. Но начиная со следующей версии «робот» научился понимать другие конфигурации экранов. Решение снять все ограничения было сознательным — нужно было увеличить разнообразие устройств на Android, пусть и за счет неизбежного увеличения количества головной боли для инженеров Google и разработчиков софта (как программистов, так и дизайнеров). Дабы головной боли было не слишком много, задачу поддержки разных экранов решили упростить и систематизировать следующим образом:
- физические размеры экранов разбиваются на диапазоны: small (от 2 до 3,5 дюймов с нестандартным соотношением сторон), normal (от 3 до 4 дюймов), large (от 4 до 7 дюймов), xlarge (от 7 до 10 дюймов)
- пиксельная плотность экранов (dpi) тоже разбивается на диапазоны: ldpi (120), mdpi (160), hdpi (240), xhdpi (320)
- производитель устройства прописывает в прошивке, в какой диапазон по размеру и плотности данное устройство попадает
- разработчик приложений включает в приложение необходимые (по его мнению) интерфейсные и графические ресурсы, рассортировав их в определенные папки, по диапазонам.
Таким образом, задача довольно сильно упрощается — когда запускается приложение, Android знает (из свойств прошивки), какие диапазоны задействованы, и берет ресурсы из нужных папок. Если ресурса для нужного диапазона нет, не беда – Android поищет ресурс с таким же названием в другой папке и приспособит его для нужного диапазона. Например, если разработчик включил в приложение только графические файлы для hdpi, а пользователь запустил приложение на устройстве с mdpi-экраном, Android просто считает соответствующий hdpi ресурс в память, ужмет его размер на треть и «отдаст» его программе. Причем «ужатая» копия будет закеширована в памяти на будущее, чтобы каждый раз, когда нужен этот ресурс, не нагружать процессор дорогостоящей операцией ужимания. Схема эта работает довольно хорошо — разработчикам даже не рекомендуется делать и включать в программу ресурсы ldpi, так как их легко сделать из ресурсов hdpi (самого популярного на данный момент диапазона) путем выкидывания каждого второго пикселя по горизонтали и вертикали.
То, что в *dpi-папки надо класть графику — очевидно. Чем выше dpi, тем больше должен быть размер картинки, чтобы она получалась примерно одинакового размера на экране. А для чего тогда нужен размер экрана? Тут все немного хитрее. Сильно утрируя, можно сказать, что он определяет «телефонность» или «планшетность» устройства. Больший физический размер экрана элементарно позволяет больше на нем разместить, что сильно влияет на количество и расположение элементов UI на экране. Хороший пример — системные настройки. На 10-дюймовом (xlarge) экране планшета, да еще в ландшафтной ориентации вполне можно разместить список настроек слева, а опции по конкретной настройке — справа. А вот на 4-дюймовом (normal) экране телефона такое не пройдет — даже в ландшафте экран телефона слишком мал, чтобы втиснуть в него два списка: будет сложно читать и тем более выбирать что-то пальцем. Вот и приходится показывать списки раздельно — сперва общий список настроек, а потом, при выборе настройки — список опций. Разбивка на диапазоны позволяет запрограммировать подобную логику довольно просто — в папку ресурсов для xlarge кладем планшетную конфигурацию UI (layout) с двумя списками на одном экране, а в папку для normal — телефонную с одним списком на каждый экран.
Интересный факт: как было сказано выше, при подборе замены для графического ресурса (картинки) Android ищет «сверху вниз», от более высоких разрешений к низким. А вот при подборе замены для раскладки UI (layout) Android идет в противоположном направлении — используется раскладка для меньшего экрана. И если первое очевидно (если нет, то растяните картинку в графическом редакторе и посмотрите, что будет с качеством), то во второе надо чуть вдуматься. Дело в том, что попытка впихнуть планшетную раскладку на телефонный экран может привести к тому, что приложением будет практически невозможно пользоваться, в то время как телефонная раскладка на экране планшета вполне функциональна, хоть и не так красива.
А теперь пара слов про размеры элементов UI в пискелях. Например, про размер шрифтов, который обычно задается в пикселях. Допустим, разработчик оптимизировал размер шрифтов под mdpi-экран в раскладке UI для телефона (размеры шрифтов живут там). А пользователь запустил приложение на телефоне с экраном этого размера, но с xhdpi-плотностью. Размер в пикселях не изменится, а вот их физический размер сильно уменьшится (задача для упорных: во сколько раз?). В результате шрифт на экране будет мелким. На помощь приходит dp — density independent pixels, пиксели, не зависящие от плотности. Это референсные пиксели, для плотности mdpi. Выбор mdpi как референсной плотности сделан из исторических соображений — первый телефон на Android имел плотность mdpi. Разработчик задает размер шрифтов (или других элементов UI) не в пикселях, а в dp. А Android, зная размер экрана для данной раскладки и отношение плотности данного экрана к референсной, сам посчитает нужный размер и увеличит размер шрифта, чтобы он был подходящего размера. Просто, как два байта переслать.
Начиная с версии 3.2 Android дает разработчику даже больший контроль над конфигурацией UI для разных экранов. Разработчик может указать «минимальную ширину» экрана, при достижении которой будет выбрана конретная раскладка, таким образом определяя диапазоны самостоятельно. Это позволяет, например, задавать разные раскладки для 7-дюймовых и 10-дюймовых планшетов. 7-дюймовые планшеты обычно имеют разрешение 600х1024, тогда как 10-дюймовые — 800х1200, в то время как по старой схеме диапазонов они оба попадали под xlarge. Как показывает практика, не все, что хорошо для 10-дюймового экрана, будет хорошо работать на 7-дюймовом. Соответственно, определяя собственные диапазоны, разработчик получает возможность создавать оптимизированные UI под каждый.
Итак, вооружившись новоприобретенными знаниями, попробуем перевести пост многоумной Дайэн на общечеловеческий язык.
Nexus 7 — это 7-дюймовый планшет, он очень похож на своих 7-дюймовых собратьев. С разницей в плотности экрана — у стандартных планшетов с разрешением 600х1024 она — mdpi, у Nexus 7 с его 800х1280 — tvdpi. В пересчете на традиционную ширину в 600 пикселей разрешение Nexus 7 получится 600х961. Если сравнить его с 600х1024, то соотношение сторон Nexus 7 будет 16:9, что не слишком отличается от стандартного 16:10. То есть по доступной площади и конфигурации экрана Nexus 7 отличается незначительно.
Еще одна проблема долой — экран Nexus 7 попадает под диапазон sw600dp (минимальная ширина экрана 600 пикселей), ориентированный как раз на 7-дюймовые планшеты. Таким образом, раскладки UI, заточенные под 7-дюймовые планшеты, будут работать на Nexus 7.
Незнакомое нам tvdpi — это новый диапазон плотности, созданный для приложений под 720p-телевизоры (для 1080p-телевизоров используется xhdpi). Но специально для него оптимизировать ничего не надо. Это «вторичное» разрешение, устройство может быть под него сконфигурировано, но разработчикам создавать отдельные графические ресурсы не рекомендуется. Как рассказывалось ранее, Android умеет изменять размер графических ресурсов, чтобы приспосабливать их для нужной плотности экрана. Именно эту способность системы и рекомендуется задействовать в данном случае. С возможными побочными явлениями (артефактами) при этом Android борется следующими методами:
- Артефакты намного меньше заметны на экранах высокого разрешения, как у Nexus 7.
- При создании графического ресурса Android обычно использует ресурсы для более высокой плотности экрана. В данном случае, скорее всего, это будет hdpi, который использует подавляющее большинство устройств, соответственно, ресурсы для него есть практически в каждом приложении.
- Планшетный UI использует иконки «на размер больше», чем данная плотность экрана. В рассматриваемом случае это опять популярный hdpi. Причем он будет использоваться в оригинальном размере, то есть с максимальным качеством.
Вот и получается, что, несмотря на новое разрешение экрана, соотношение сторон и плотность, девелоперам особо ничего не надо делать, чтобы их приложения работали на Nexus 7 и при этом нормально выглядели. Дайэн пишет, что Nexus 7 послужил отличным тестом возможностей Android приспосабливаться к разным экранам. При создании UI Jelly Bean им пришлось создать только один графический ресурс tvdpi — для фона выпадающей панели уведомлений.
Автор — инженер Samsung Mobile USA