Comments 57
Как разруливаете ситуацию с адоптацией UI под разные размеры экрана и разрешения?
0
Зависит от проекта. В основном, руководствуемся гайдом от Qt.
Но были проекты, например, где разработка сначала идёт под десктоп, а потом уже переносится на iOS/Android/WP. Из-за наличия большой кодовой базы просто масштабировали основной экран приложения, сохраняя пропорции (это применимо для планшетов в ландшафтной ориентации).
Ну и последнее, но не самое красивое решение — это при первоначальной загрузке высчитывать высоту базовой строки исходя из размеров экрана. А из этой базовой высоты уже строится высота всех остальных элементов. Тут нужно отметить, что если вы поддерживаете смарфтоны, то высоту лучше считать из портретной ориентации и не пересчитывать при повороте устройства, иначе в ландшафтной всё будет оч.мелко.
Но были проекты, например, где разработка сначала идёт под десктоп, а потом уже переносится на iOS/Android/WP. Из-за наличия большой кодовой базы просто масштабировали основной экран приложения, сохраняя пропорции (это применимо для планшетов в ландшафтной ориентации).
Ну и последнее, но не самое красивое решение — это при первоначальной загрузке высчитывать высоту базовой строки исходя из размеров экрана. А из этой базовой высоты уже строится высота всех остальных элементов. Тут нужно отметить, что если вы поддерживаете смарфтоны, то высоту лучше считать из портретной ориентации и не пересчитывать при повороте устройства, иначе в ландшафтной всё будет оч.мелко.
+1
Так, в нескольких приложениях мы просто насовсем отключали клавиатуру и писали свою на базе Qt Virtual Keyboard
Это очень сильно пугает. У меня установлена кастомная клавиатура (нестандартная), и что, она работать не будет, и мне будут показывать обычную QWERTY?
+1
Тут всё зависит от задачи, если приложение представляет из себя татарско-русский словарь, пользователю было бы удобнее не искать клавиатуру в плеймаркете/аппсторе/винсторе (тем более, если её там нет), либо добавлять через настройки нужный язык (тем более, если его в настройках нет) а пользоваться приложением сразу с интегрированной клавиатурой.
Мы на этот счёт проводили исследования на целевой группе, никто не смог найти и скачать кастомную клавиатуру из маркетов без подсказки. Жизнь приложения заканчивалась на фразе "блин, тут ещё чё-то ставить/настраивать надо" в случае с обучалкой, где рассказно, как поставить клавиатуру, либо "блин, а как тут вводить буквы-то" без обучалки.
Естественнно, если приложение не узко-специализированно, то нужно использовать стандартную клавиатуру.
Мы на этот счёт проводили исследования на целевой группе, никто не смог найти и скачать кастомную клавиатуру из маркетов без подсказки. Жизнь приложения заканчивалась на фразе "блин, тут ещё чё-то ставить/настраивать надо" в случае с обучалкой, где рассказно, как поставить клавиатуру, либо "блин, а как тут вводить буквы-то" без обучалки.
Естественнно, если приложение не узко-специализированно, то нужно использовать стандартную клавиатуру.
+2
Самая сладость начинается тогда, когда нужно использовать разные версии NDK с учётом различных API, которые там представлены. Пытался использовать функции из posix для привязки треда к физическому ядру процессора с учётом cpu affinity — испытал непередаваемое удовольствие.
0
А приходилось ли сталкиваться с ситуацией, когда в приложении под Android, написанном на Qt, есть и foreground сервисы, и активити?
0
не выбирайте Qt/Qml!
Получается, вы используете QWidget и его потомков? Скажите, как он сейчас работает под android?
Я когда-то давно, когда порт под андроид еще назывался Necessitas, пытался с ними работать (точнее, просто откомпиллил виндово-убунтовое приложение) и столкнулся с тем что этот путь был совершенно непригоден т.к. виджеты были не адаптированы под тач, например, QTableView и, кажется, скролл имели крайне мелкие размеры скроллбаров, а диалог открытия файлов не ресайзился под экран и был раза этак в 2 больше телефона размером, при этом штатный путь кастомизации через QStyle попросту не срабатывал. В итоге плюнул и постепенно переписал приложение на QML, благо это домашний проект и чего сверхсложного там не было и нет.
Из сложностей — постоянно натыкаюсь на всяческие мелкие баги в контролах, то у ComboBox'а принципиально нельзя програмно выставить пустую строку (если присвоить comboBox1.currentIndex = индекс пустой строки текст попросту не меняется), то файловый диалог возвращает в винте пути в виде /C:/Users/myFile.txt которые едят не все компоненты qt работающие с путями (конкретно QFile), то еще что. В целом вроде и мелочи, но раздражает, хотя я бы все равно сказал что это классная библиотека.
Кстати, еще интересный вопрос — есть ли какой-то способ использовать разные элементы для разных платформ из qml? Вариант с подгрузкой через js я знаю, но мне он кажется несколько костыльным
Получается, вы используете QWidget и его потомков? Скажите, как он сейчас работает под android?
Я когда-то давно, когда порт под андроид еще назывался Necessitas, пытался с ними работать (точнее, просто откомпиллил виндово-убунтовое приложение) и столкнулся с тем что этот путь был совершенно непригоден т.к. виджеты были не адаптированы под тач, например, QTableView и, кажется, скролл имели крайне мелкие размеры скроллбаров, а диалог открытия файлов не ресайзился под экран и был раза этак в 2 больше телефона размером, при этом штатный путь кастомизации через QStyle попросту не срабатывал. В итоге плюнул и постепенно переписал приложение на QML, благо это домашний проект и чего сверхсложного там не было и нет.
Из сложностей — постоянно натыкаюсь на всяческие мелкие баги в контролах, то у ComboBox'а принципиально нельзя програмно выставить пустую строку (если присвоить comboBox1.currentIndex = индекс пустой строки текст попросту не меняется), то файловый диалог возвращает в винте пути в виде /C:/Users/myFile.txt которые едят не все компоненты qt работающие с путями (конкретно QFile), то еще что. В целом вроде и мелочи, но раздражает, хотя я бы все равно сказал что это классная библиотека.
Кстати, еще интересный вопрос — есть ли какой-то способ использовать разные элементы для разных платформ из qml? Вариант с подгрузкой через js я знаю, но мне он кажется несколько костыльным
+1
Я не использую активно виджеты, поэтому написал именно про QML. Возможно, с QWidget есть способы это решить и потом внедрить решение в QML сцену.
По поводу второго вопроса не совсем понял, можно использовать Loader с указанием какие конкретно виджеты подгружать. В этом плане полезно смотреть на исходники Quick.Controls, как они там это решают.
По поводу второго вопроса не совсем понял, можно использовать Loader с указанием какие конкретно виджеты подгружать. В этом плане полезно смотреть на исходники Quick.Controls, как они там это решают.
0
А что же вы тогда имели в виду под "не выбирайте Qt/Qml"? Я как-то считал что когда речь идет о GUI на Qt, то можно использовать либо QWidget'ы, либо qml, либо же их комбинацию.
По поводу второго вопроса, да, про loader'ы я забыл, надо будет попробовать. Хотя у меня такой финт может быть и не пройдет — мне надо было загрузить разные меню для андроида и десктопа и хотелось написать что-то вида:
ApplicationWindow {
…
menuBar: Qt.platform.os == "android"? AndroidMenu{}:DesktopMenu{}
…
}
По поводу второго вопроса, да, про loader'ы я забыл, надо будет попробовать. Хотя у меня такой финт может быть и не пройдет — мне надо было загрузить разные меню для андроида и десктопа и хотелось написать что-то вида:
ApplicationWindow {
…
menuBar: Qt.platform.os == "android"? AndroidMenu{}:DesktopMenu{}
…
}
0
Когда я говорил про Не выбирайте Qt/Qml я хотел сказать, что не выбирайте его в качестве технологии для построения UI вашего мобильного приложения на Android если вам нужно очень много работать с текстом привычными для Android-пользователя методами.
Есть классная игра — VoltAir, сделанная ребятами из Google на базе QtQuick, в ней нет много работы с текстом — вот для этих целей, с моей точки зрения, Qml идеален (с учётом кроссплатформенности). Ради справедливости стоит отметить, если я не ошибаюсь, что ребята из Google правда подхачили немного исходники.
Есть классная игра — VoltAir, сделанная ребятами из Google на базе QtQuick, в ней нет много работы с текстом — вот для этих целей, с моей точки зрения, Qml идеален (с учётом кроссплатформенности). Ради справедливости стоит отметить, если я не ошибаюсь, что ребята из Google правда подхачили немного исходники.
+1
В своем проекте использовал кастомные Qml компоненты, которые были реализованы в виде плагинов с общим интерфейсом. Правда проект был не нацелен на мобильные платформы, но думаю подобный подход использовать можно, назначив каждой платформе свой компонент.
0
То что можно понятно и я так и делаю, но самый простой способ который я смог найти был загрузка того или иного файла (не в виде плагина, а просто в виде отдельного qml которые отличаются для разных платформ) при помощи js через Qt.createComponent(), и я как раз хотел узнать есть ли более правильный способ.
0
Не знаю чем собираются Qt проекты под андроид но в CMake можно указать какую директорию в проект добавить в зависимости от ОС. По директориям распихать компоненты. CMake я правда взял исключительно ради возможности пользоваться CLion. И не уверен стоит ли такой подход затраченого времени в вашем случае.
0
qmake, и там тоже есть такая возможность. Другое дело, что придется подключать эти директории непосредственно в QML, а вот там препроцессора на импорты нет.
0
в QML нужно импортировать компонент, а не директорию. Если в соответствующих разным ОС директориях лежат компоненты с одинаковым названием, то в QML ничего не меняется. По крайней мере с плагинами это работает, не могу придумать причину почему не будет работать напрямую.
0
Даже если мы хотим импортировать компонент, а не папку целиком, нужно в импорте прописать путь до него, который будет отличаться.
0
Если правильно понял разговор, то в CMake добавляется что-то типа:
if(UNIX)
install(FILES qml/unix/Foo.qml
DESTINATION qml)
elseif(WIN32)
install(FILES qml/win/Foo.qml
DESTINATION qml)
endif()
0
Не лучший вариант на самом деле, если нужно поправить платформоспецифичный компонент, обратно его после тестирования придется руками копировать. Это ладно, один, а если 3-5...
0
Я имел в виду что-то типа такого: в каждой папке реализован компонент.
В основной программе регистрируем кастомный тип:
в QML используем:
файл ресурсов подключается в зависимости от ОС
В основной программе регистрируем кастомный тип:
const QUrl MyClass("qrc:/qml/MyClass.qml");
qmlRegisterType<MyClass>("com.mycompany.mycomponents", 1, 0, "MyClass");
в QML используем:
import com.mycompany.mycomponents 1.0
MyClass {}
файл ресурсов подключается в зависимости от ОС
+1
А в файле ресурсов прописываем алиасы, чтобы нивелировать различие путей, да. На самом деле хорошее решение, кода выйдет чуть меньше.
Я говорил именно про подключение напрямую внутри .qml файлов, без регистрации типов в плюсах, там альтернатив Qt.createComponent() нет, но оно не сильно напрягает.
Я говорил именно про подключение напрямую внутри .qml файлов, без регистрации типов в плюсах, там альтернатив Qt.createComponent() нет, но оно не сильно напрягает.
0
Посмотрите в сторону Loader http://doc.qt.io/qt-5/qml-qtquick-loader.html
Думаю будет удобнее чем Qt.createComponent().
Справедливости ради: Предложение zmeykas подменять файлы при сборке мне нравится больше.
Думаю будет удобнее чем Qt.createComponent().
Справедливости ради: Предложение zmeykas подменять файлы при сборке мне нравится больше.
0
И чем Loader будет удобнее?
0
Тем, что GUI будет описан декларативно.
0
Он и так описан декларативно, просто подгружаем разные файлы:
Component.onCompleted: {
var menuComponent;
if (core.isIOS) {
menuComponent = Qt.createComponent("IosNavigationTabBar.qml");
menu = menuComponent.createObject(panelApplication);
}
else {
menuComponent = Qt.createComponent("AndroidNavigationTabBar.qml");
menu = menuComponent.createObject(mainActionBar);
}
}
0
Аналог этого кода:
Loader { source = (core.isIOS) ? "IosNavigationTabBar.qml" : "AndroidNavigationTabBar.qml" }
0
Вы можете заметить, что у компонентов разные родители, соответственно отображаются они в разных частях экрана.
0
да, этот момент я действительно просмотрел. Можно "засунуть" лоадеры в те места, которым принадлежат загружаемые компоненты, например:
Просто я считаю использование Qt.createComponent моветоном — оно нарушает декларативность
Loader {
source: "IosNavigationTabBar.qml"
active: core.isIOS
}
Просто я считаю использование Qt.createComponent моветоном — оно нарушает декларативность
0
Можно, но зачем? Почему вы так считаете?
0
- В иерархии QML-файла компоненты создаются там же, где они отображаются.
- Код лаконичнее
- Свойства объекта задаются прямо в лоадере. createObject же задает свойства создаваемого объекта а. списком, б. по значению
Например, вот здесь: http://doc.qt.io/qt-5/qml-qtquick-loader.html#sourceComponent-prop
достаточно красивый пример правильного, на мой взгляд (и взгляд разработчиков Qt), использования динамической загрузки компонентов
+1
- Да
- В простейшем случае — да. В сложном же — работа со свойствами и сигналами компонента в лоадере усложняется.
- В лоадере по сути тоже списком, просто он обычно представлен по одному выражению в строке ;)
Сложно представить, что на странице документации по Loader будет что-то другое. Вот страница по динамическому созданию от тех же разработчиков.
В целом я с вами согласен, что в простых случаях Loader предпочтительнее.
0
в Qt 5 нет возможности вставлять QWidget'ы в QtQuick сцену: stackoverflow.com/questions/13014415/qt5-embed-qwidget-object-in-qml
Qt уходят от классических виджетов, и не просто так. QML проще в разработке, быстрее в рендеринге, да и кастомизируются проще.
Qt уходят от классических виджетов, и не просто так. QML проще в разработке, быстрее в рендеринге, да и кастомизируются проще.
+1
Только SVG поддерживается не полностью. Есть очень хорошие векторные иконки Oxygen Icons (https://www.archlinux.org/packages/extra/any/oxygen-icons/). Но использовать их нормально не получается…
Вот цитата из документации (http://doc.qt.io/qt-5/svgrendering.html):
Qt supports the static features of SVG 1.2 Tiny.
Так что простая SVG графика отображается без проблем, а что-то сложнее — коверкается.
Вот цитата из документации (http://doc.qt.io/qt-5/svgrendering.html):
Qt supports the static features of SVG 1.2 Tiny.
Так что простая SVG графика отображается без проблем, а что-то сложнее — коверкается.
0
Согласен, но мы использовали статичные, вместо картинок. Допустим, удобно для стилизованных флагов с градиентом, внедрённых в форму, придуманную дизайнером. Основным бонусом для нас — было избавление от "чудных мнгновений", потраченных на ресайз картинок (хотя imagemagick и скрипты в этом помогает, но потом всё равно вручную их надо отсматривать и находить и исправлять "поковерканные" при ресайзе).
К слову сказать, нынешние VectorDrawables для Android тоже не идеальны. В Qt с этим проще.
К слову сказать, нынешние VectorDrawables для Android тоже не идеальны. В Qt с этим проще.
+1
Спасибо за статью. Я в свое время столкнулся тоже с некоторыми проблемами, что привело к появлению собственных велосипедов. Может они будут полезны и Вам в чем-то:
Не радует конечно, что очень много приходится делать с нуля при разработке на Qt под мобильные платформы, но как правило весь новый код затем можно переиспользовать почти везде.
- https://github.com/kafeg/qtrest — полноценный REST клиент, который умеет автоматически маппить JSON/XML в наследника QAbstractListModel, обрабатывать fetchMore и canFetchMore для пагинации, умеет передавать параметры сортировки и фильтрации и прочие нужные фишки. Имеет интерфейс из C++ и QML. Из коробки умеет работать с Yii2 REST API и Django REST Framework (ну как умеет, по их лекалам сделан =) ). Пока в полубете, много еще чего нужно сделать.
- https://github.com/kafeg/adctl — QtAdMob и Google Play Game Services для Qml.
Не радует конечно, что очень много приходится делать с нуля при разработке на Qt под мобильные платформы, но как правило весь новый код затем можно переиспользовать почти везде.
+2
Неплохо, а почему не строить работу с REST через WorkerScript и обычный Ajax? Если там возвращается JSON — то это очень просто и удобно. Ну и есть ListModel sync (если не нужны всякие фишки с сортировкой, fetchMore и т.д., которыми можно нагрузить разработчика серверной части).
0
Хотелось один раз сделать все полноценно. Почти в каждом проекте работающем с API есть стандартная потребность в получении данных и их сортировке/фильтрации/подгрузке, так и в отправке POST/PUT запросов. Плюс мне хотелось иметь доступ к моделям как из QML так и из C++ и располагать всеми средствами для предобработки данных из C++.
На JS можно было бы реализовать такую логику, но мне кажется код получился бы гораздо сложнее.
Сейчас, если Вы обратили внимание в репозитории описан сложный метод использования библиотеки — через создание производного класса. На самом же деле я планирую еще создать какой-нибудь простой QML-компонент для модели, чтобы ему модно было лишь передать параметр и показать API-метод из которого стоит брать данные. В этом случае программисту нужно будет лишь унаследовать и реализовать класс работы со своим API.
На JS можно было бы реализовать такую логику, но мне кажется код получился бы гораздо сложнее.
Сейчас, если Вы обратили внимание в репозитории описан сложный метод использования библиотеки — через создание производного класса. На самом же деле я планирую еще создать какой-нибудь простой QML-компонент для модели, чтобы ему модно было лишь передать параметр и показать API-метод из которого стоит брать данные. В этом случае программисту нужно будет лишь унаследовать и реализовать класс работы со своим API.
0
А как вы решаете момент с черным экраном при запуске Qt Quick приложения на Android?
0
Ну какой-то момент будет черным в любом случае, потом можно показывать картинку splash screen, задается стандартным образом в манифесте.
0
Мы используем плавную анимацию opacity контейнера с контентом и фоновым цветом от 0 до 1. В итоге эффект следующий (он не совсем решает проблему, но немного улучшает поведение приложения): чёрный экран и плавное появление интерфейса вашего приложения.
+1
Самое важное не написали: модуль QtLocation очень скуден для реального использования. По факту, подходит для демо тулзы с тайловой картой osm/here/mapbox, и эта карта даже не поддерживает вращения (bearing). Можно написать геоплагин, предоставляющий тайлы, это в принципе несложно. Но если же вы хотите написать свою векторную карту на основе QML Map, будьте готовы, что от оригинального кода QtLocation у вас останутся лишь формулы пересчета пикселей сцены в координаты.
+2
Спасибо за разъяснения. Опыта работы как такового под Android/iOS/WP с QtLocation не было. Когда только начинал интегрироваться с "железными фичами", такими как камера — понял, что оно далеко от идеала, в связи с чем работу с сенсорами, гео, блютуз, камерой и прочим строю исключительно на базе нативных компонентов и уже при необходимости передаю результат обратно в Qt.
Поделитесь, пожалуйста, опытом сравнения с нативными аналогами.
Поделитесь, пожалуйста, опытом сравнения с нативными аналогами.
+1
По первой проблеме есть вполне себе готовое решение для андроида.
Можно использовать обертки над нативными полями ввода.
https://gitlab.com/2gisqtandroid/qtandroidextensions/tree/master/QtOffscreenViews
Можно использовать обертки над нативными полями ввода.
https://gitlab.com/2gisqtandroid/qtandroidextensions/tree/master/QtOffscreenViews
+2
Попробовал, да, действительно, проблема с тестом и Emoji решается. Насколько большой опыт использования у вас этой компоненты? Есть ли какие-то камни и т.д.?
И не знаете ли, почему они не используют это решение в своём Android приложении?
И не знаете ли, почему они не используют это решение в своём Android приложении?
0
Sign up to leave a comment.
Радость и грусть разработки на Qt под Android (и не только)