Отже, продовжуємо реалізовувати однаковий функціонал у додатках під Android із двох принципово різних світів. А саме на традиційній Java і менш поширеній Qt QML C++.
На цей раз реалізуємо меню в ActionBar активіті. Зазначу, що ActionBar для варіанта з QML доведеться писати самостійно, оскільки такого елемента Qt QML немає, але він реалізується через компонент ToolBar. Оскільки цей момент був описаний в уроці про Hello World , то в даному уроці ретельно зупинятися на ньому не будемо, тільки винесемо ActionBar в окремий файл QML, зробивши його окремим типом QML і додамо до нього іконку меню, за натисканням на яку викликатимемо меню.
Меню буде наступною структурою:
- Інформація
- Перший
- Другий
- Про
У центрі вікна програми повинен бути текст, який замінюватиметься іншим текстом при натисканні наступних пунктів меню
- Спочатку
- Другий
- Про
Зовнішній вигляд меню на Java
Перший рівень
Другий рівень
Зовнішній вигляд меню на Qt QML
Перший рівень
Другий рівень
Реалізація JAVA
menu.xml
Для верстки меню необхідно створити XML файл, який розташовуватиметься в ресурсному каталозі menu. Так і назвемо його menu.xml
Тут все досить просто, є невелика верстка з назвами пунктів меню, вкладеними елементами та id, якими можна буде звернутися до даних пунктів з Java коду.
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/informationItem" android:title="Information"> <menu> <item android:id="@+id/firstInfoItem" android:title="First" /> <item android:id="@+id/secondInfoItem" android:title="Second" /> </menu> </item> <item android:id="@+id/aboutItem" android:title="About" /> </menu>
activity_main.xml
Далі йде верстка самої активіті, яка в даному випадку створена за умовчанням.
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.evileg.javamenu.MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
MainActivity.java
А тепер потрібно ініціалізувати всі компоненти меню та навішувати на них обробник події кліка.
package com.evileg.javamenu; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends Activity { // Объявим объекты всех пунктов меню MenuItem aboutItem; MenuItem firstInfoItem; MenuItem secondInfoItem; // А также текстового поля, в которое будем устанавливать текст TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); // найдём данное текстовое поле в ресурсах } // Создадим обработчики пунктов меню @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu, menu); // Найдём все элементы пунктов меню aboutItem = menu.findItem(R.id.aboutItem); firstInfoItem = menu.findItem(R.id.firstInfoItem); secondInfoItem = menu.findItem(R.id.secondInfoItem); // Создадим обработчик кликов по пунктам меню MenuItem.OnMenuItemClickListener onMenuClickListener = new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.aboutItem: textView.setText("About Menu Item is pressed"); break; case R.id.firstInfoItem: textView.setText("First Info Item is pressed"); break; case R.id.secondInfoItem: textView.setText("Second Info Item is pressed"); break; } return true; } }; // Установим этот обработчик на пункты меню aboutItem.setOnMenuItemClickListener(onMenuClickListener); firstInfoItem.setOnMenuItemClickListener(onMenuClickListener); secondInfoItem.setOnMenuItemClickListener(onMenuClickListener); return true; } }
Реалізація Qt QML
ActionBar.qml
Я створив спеціальний тип ActionBar в окремому файлі QML, щоб виділити його з основного файлу main.qml. Це дозволить відокремити цей код від решти корисної частини коду, яка має показати відмінність реалізацій меню на Java та Qt QML. Також цей ActionBar буде використовуватися в наступних статтях.
Зверніть увагу на сигнал menuClicked , цей сигнал буде викликатись у ActionBar, коли користувач натисне пальцем на MouseArea, яка відповідає за клік по нашій кастомній кнопці меню. За цим сигналом буде відкрито меню, розташоване у файлі main.qml
import QtQuick 2.10 import QtQuick.Controls 2.3 import QtQuick.Controls.Material 2.1 ToolBar { id: root height: 48 signal menuClicked() // Сигнал, который сообщит о клике по кнопке меню Rectangle { anchors.fill: parent color: "#080808" Image { id: ico height: 36 width: 36 anchors { left: parent.left leftMargin: 10 top: parent.top topMargin: 6 } source: "qrc:/icons/ic_launcher.png" } Text { anchors { verticalCenter: parent.verticalCenter left: ico.right leftMargin: 4 } text: qsTr("QMLMenu") font.pixelSize: 18 color: "white" } // Начало реализации кнопки меню Rectangle { width: height color: menuArea.pressed ? "#55ffffff" : "transparent" anchors { top: parent.top right: parent.right bottom: parent.bottom } Image { id: menuIcon height: 36 width: 36 anchors { centerIn: parent } source: "qrc:/icons/menu.png" } MouseArea { id: menuArea anchors.fill: parent onClicked: root.menuClicked() } } // конец реализации кнопки меню } }
main.qml
А тут буде вміщено код того, заради чого і писався цей урок. Показати, як реалізувати саме меню.
import QtQuick 2.10 import QtQuick.Window 2.10 import QtQuick.Controls 2.3 import QtQuick.Controls.Material 2.1 ApplicationWindow { id: root visible: true width: 360 height: 520 title: qsTr("QML Menu") // Добавляем ActionBar в окно приложения header: ActionBar { onMenuClicked: actionBarMenu.open() // Открываем меню // Добавляем меню Menu { id: actionBarMenu // С указанием расположения, чтобы Menu выскакивало в том же месте, // что и в варианте с Java x: root.width y: 48 Menu { title: qsTr("Information") Action { text: qsTr("First") // Обработка клика по меню onTriggered: label.text = qsTr("First Info Item is pressed") } Action { text: qsTr("Second") onTriggered: label.text = qsTr("Second Info Item is pressed") } } Action { text: qsTr("About") onTriggered: label.text = qsTr("About Menu Item is pressed") } } } Label { id: label anchors.centerIn: parent text: qsTr("Hello World!") font.pixelSize: 14 } }
Висновок
Звичайно, є деяка різниця в реалізації меню за замовчуванням для Java і Qt QML, наприклад наявність заголовка підменю. Теоретично в QML це можна реалізувати за допомогою порожнього Action, який матиме title, буде трохи кастомізований і нічого не робитиме при кліку, але чи потрібно це?
Добрый день.
Как в такое меню добавить картинку и просто лэйблы с текстом?
И скажите пожалуйста как связаны ActionBar.qml и main.qml?
Превый файл скопировал, в другой qml вставил этот код, но меню не появляется
Вот так работает
У объектов MenuItem есть свойства iconName и iconSource. В iconSource можно добавить иконку из ресурсов в проекте. Можете воспользоваться этим свойством и тогда у вас будут в пунктах меню и иконки и текст.