Итак, продолжаем реализовывать одинаковый функционал в приложениях под Android из двух принципиально различных миров. А именно на традиционной Java и менее распространённом Qt QML C++.
На этот раз реализуем меню в ActionBar активити. Отмечу, что ActionBar для варианта с QML придётся писать самостоятельно, поскольку такого элемента в Qt QML нет, но он реализуется через компонент ToolBar. Поскольку этот момент был описан в уроке про Hello World , то в данном уроке тщательно останавливаться на нём не будем, только вынесем ActionBar в отдельный QML файл, сделав его отдельным типом QML и добавим в него иконку меню, по нажатию на которую будем вызывать меню.
Меню будет следующую структуру:
- Information
- First
- Second
- About
В центре окна приложения должен быть текст, который будет заменяться другим текстом при нажатии следующие пункты меню
- First
- Second
- About
Внешний вид меню на 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 можно добавить иконку из ресурсов в проекте. Можете воспользоваться этим свойством и тогда у вас будут в пунктах меню и иконки и текст.