Скорей, надо скорей писать код! Как театр начинается с вешалки, так и любой клиент ВсёМоё начинается с окошка логина. Надо его нарисовать!
Для начала выдираем скриншотом, прямо из эмулятора, работащий логин.
В оригинале всё, кроме полей ввода и чекбокса, нарисовано прямо на бэкграунде. С одной стороны, это хорошо и уменьшает объем кода. А с другой стороны, ограничивает нарисованным. А ведь охота нарисовать сразу для всех платформ. Ну или практически для всех …
Разбиваем окошко на следующие элементы: бэкграунд, “банка”, логотип, и два поля ввода. Для десктопа еще должна добавиться кнопка “Войти”, ибо на мобильных её функцию выполняет кнопка на виртуальной клавиатуре. Кнопку “регистрация” … а нехай будет
В общем, как-то так получается в реальности.
Берем Qt Creator и создаем в нем проект, который использует QtQuick.Controls. Мне он поугрожал, что использовать полученное можно будет только с версией iOS больше 5.1 … но найдите мне такую версию живьем?
Создаем в нем фаил ресурсов и загоняем туда картинки, тупо выдранные из оригинала (красоту будем наводить потом).
Для начала нам надо добиться, что бы один и тот же код выполнялся и под десктопом и под айфончиком.
Для этого надо:
а) загнать qml в ресурсы
б) нафиг сменить процедуру загрузки, иначе будут ошибки про not ready и прочее. Короче QTBUG-29873
main.cpp сейчас у меня выглядит так
Красивая картинка? Полностью полученное можно посмотреть где положено (то есть в git и нефиг ныть!), а у меня получилось следующее:
Поверьте, на андроиде примерно тоже самое. Теперь необходимо осуществить … гламуризацию всего этого дела. Например, где кнопочка “регистрация” (и нужна ли она)? И все криво при повороте набок. И пароль набирается видимыми буквами. И нету чекбокса. И вообще, все криво.
В общем, надо сделать так, что бы элементы меняли свое положение относительно друг друга при изменении соотношения сторон. Это происходит либо когда окошко у десктопа таскают мышкой, либо мобильник переворачивают.
Для начала убираем всякие Column { и тупо прописываем все подряд. Затем добавляем State почти по инструкции http://doc.qt.digia.com/qtquick-components-symbian-1.1/qt-components-scalability-guidelines-orientation-specific-layouts.html
Так как там немного древнее, я заиспользовал одну StateGroup, без отдельной с when:true
StateGroup {
states: [
State {
when: (main.width / main.height) < 1.00
PropertyChanges {
target: loginEmail; text: "portrait"
}
AnchorChanges { target: logoImage; anchors.top: parent.top }
AnchorChanges { target: loginEmail; anchors.top: logoImage.bottom }
// AnchorChanges { target: userPassword; anchors.top: loginEmail.bottom }
},
State {
when: (main.width / main.height) > 1.00
PropertyChanges {
target: loginEmail; text: "landscape"
}
AnchorChanges { target: loginEmail; anchors.top: logoImage.bottom }
// AnchorChanges { target: userPassword; anchors.left: loginEmail.right }
}
]
}
Для проверки я тупо убрал лишнее и в поле для логина начал выводить, какой же State используется. И потом, с помощью PropertyChanges и AnchorChanges я меняю свойства и привязки элементов. В итоге получается “адаптивный” дизайн.
Вот теперь можно и добавить кнопки про регистрацию и вперде!
Правда, вперде прямо сразу не получится. По двум причинам.
Во-первых, для десктопа и мобильного необходимо разные расположения элементов. На мобильном половину (ну или часть) экрана занимает клавиатура, а на десктопе нет. Виндовсные планшеты пока не рассматриваем, их слишком мало, что бы быть принятыми во внимание. И если использовать одну и ту же схему размещения элементов, то либо на мобильном будет криво, либо на десктопе. Некрасиво.
Во-вторых, это долбанное разнообразие разрешений и форматов экрана. У кого-то 4:3, а у кого-то 16:9. Кому-то хватает 640х480 или даже 320 на 240, а кому-то и 1920 на 1080 не хватает.
Что делать?
После некоторого раздумья я решил, что фиг с этими пропорциями. Пусть будет просто две ориентации экрана: горизонтальная и вертикальная.
Для определения платформы (мобильная или десктопная) проще всего использовать предопределенные константы прямо из Qt. напрямую из QML не получится, слишком кроссплатформенный он получился …
Итак, что имеем?
1. ориентацию экрана легко узнать из самого QML. Просто по соотношению высоты и ширины экрана.
2. Ориентацию элементов управления (для мобильного прижимаем кверху, а для десктопа – центрируем) передаем в QML снаружи. Делать свой QML для каждой платформы – моветон.
3. Для удобства позиционирования волевым решением принимаю, что экран в горизонтальной ориентации в реальности имеет размеры 40х30. Кто-то это называет device independed pixels, кто units, кто еще как. И все координаты будут преобразовываться в реальные пикселы отдельной функцией. Сначала засуну ее в QML, а там посмотрим.
Ну, пункт 1 сделан еще на подготовительном этапе.
Теперь надо передать платформу в QML. Обычно народ сразу хватается за классы, но нам-то по идее хватит что-нибудь типа 0 – по центру, 1 – прижимать все вверх.
Для этого тупо устанавливаем переменную для QML
engine.rootContext()->setContextProperty(“platform”,31);
Теперь везде можно использовать platform. Ну и для порядку неплохо бы обернуть все это в обертку из #define
int platform=0;
#ifdef Q_OS_ANDROID
platform=1;
#endif
#ifdef Q_OS_IOS
platform=1;
#endif
#ifdef Q_OS_WINPHONE
platform=1;
#endif
Потом как-нибудь можно будет сделать более тонкое разделение по платформам.
Что касается пикселов, то это решается еще проще.
Где-нибудь в начале QML, сразу после ApplicationWindow вставляю следующее:
property int guxSize: width/40
property int guySize: height/30
function gux(c)
{
return guxSize*c;
}
function guy(c)
{
return guySize*c;
}
Потом везде, где надо привязаться к координатам, использую gux для х/ширины и guy для y/высоты. Опять же, потом мне ничего не мешает переопределить подсчет этих значений для более тонкого соответствия какому-нибудь хитровыделанному дисплею.
Ну а теперь пора переходить к определению элементов и их размеров. При этом крайне рекомендую внутри элемента описаться на его ширину/высоту, а не на guy/gux. Просто потом будет гораздо легче. И никаких pointSize! Только pixelSize.
Как это выглядит в коде, вы можете увидеть в Stage1. В реальности это выглядит так:
Для “десктопа”
Для “портретного” режима
Можете поизменять размеры окошка и увидеть, как меняется местоположение элементов. Конечно, потом это надо отдать дизайнеру, что бы он своим дизайнерским чутьем подвигал всё туда-сюда, поменял цвета и поделал прочие штуки. На данном этапе важнее функционал.
И да, можно загрузить полученное в телефончик/планшетик и посмотреть, как оно будет выглядеть там. Ну и похвастаться кому-нибудь из знакомых. Всё-таки у вас в руках по настоящему кросс-платформенное приложение.