Qt Quick für Android Studio-Projekte

Übersicht

Dieses Beispiel enthält ein QML-Projekt, das Sie mit dem Qt Tools for Android Studio-Plugin in Android Studio importieren können, sowie Java- und Kotlin-Projekte, die das QML-Projekt als Ansicht verwenden, indem sie die QtQuickView-API nutzen.

Weitere Informationen darüber, wie QML funktioniert, finden Sie in der Qt Qml. Diese Dokumentation wird sich darauf konzentrieren, wie eine QML-Komponente in Java- und Kotlin-basierte Android-Anwendungen eingebettet wird.

Zunächst schauen wir uns die MainActivity's onCreate() Methode der Java- und Kotlin-Projekte an.

Für ein Java-basiertes Projekt:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    m_mainLinear = findViewById(R.id.mainLinear);
    m_getPropertyValueText = findViewById(R.id.getPropertyValueText);
    m_qmlStatus = findViewById(R.id.qmlStatusText);
    m_androidControlsLayout = findViewById(R.id.javaLinear);
    m_box = findViewById(R.id.qmlColorBox);
    m_switch = findViewById(R.id.disconnectQmlListenerSwitch);
    m_switch.setOnClickListener(view -> switchListener());
    m_qtQuickView = new QtQuickView(this);

    // Set status change listener for m_qmlView
    // listener implemented below in OnStatusChanged
    m_mainQmlContent.setStatusChangeListener(this);
    m_secondQmlContent.setStatusChangeListener(this);
    ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    m_qmlFrameLayout = findViewById(R.id.qmlFrame);
    m_qmlFrameLayout.addView(m_qtQuickView, params);
    m_qtQuickView.loadContent(m_mainQmlContent);

    Button m_changeColorButton = findViewById(R.id.changeQmlColorButton);
    m_changeColorButton.setOnClickListener(view -> onClickListener());
    Button m_loadMainQmlButton = findViewById(R.id.loadMainQml);
    m_loadMainQmlButton.setOnClickListener(view -> loadMainQml());
    Button m_loadSecondQmlButton = findViewById(R.id.loadSecondQml);
    m_loadSecondQmlButton.setOnClickListener(view -> loadSecondQml());
    Button m_rotateQmlGridButton = findViewById(R.id.rotateQmlGridButton);
    m_rotateQmlGridButton.setOnClickListener(view -> rotateQmlGrid());

    // Check target device orientation on launch
    handleOrientationChanges();
}

Für ein Kotlin-basiertes Projekt:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    m_binding = ActivityMainBinding.inflate(layoutInflater)
    val view = m_binding.root
    setContentView(view)

    m_binding.disconnectQmlListenerSwitch.setOnClickListener { switchListener() }

    m_qtQuickView = QtQuickView(this)

    // Set status change listener for m_qmlView
    // listener implemented below in OnStatusChanged
    m_mainQmlContent.setStatusChangeListener(this)
    m_secondQmlContent.setStatusChangeListener(this)

    val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
    )
    m_binding.qmlFrame.addView(m_qtQuickView, params)
    m_qtQuickView!!.loadContent(m_mainQmlContent)

    m_binding.changeQmlColorButton.setOnClickListener { onClickListener() }
    m_binding.loadMainQml.setOnClickListener { loadMainQml() }
    m_binding.loadSecondQml.setOnClickListener { loadSecondQml() }
    m_binding.rotateQmlGridButton.setOnClickListener { rotateQmlGrid() }

    // Check target device orientation on launch
    handleOrientationChanges()
}

Hinweis: Im Kotlin-Projekt verwenden wir View-Binding, um auf die UI-Komponenten der Anwendung zuzugreifen:

m_binding = ActivityMainBinding.inflate(layoutInflater)
val view = m_binding.root
setContentView(view)

Innerhalb der Methode onCreate() wird eine zuvor deklarierte Variable m_qtQuickView mit einer neuen QtQuickView initialisiert. Diese neue Instanz von QtQuickView wird erstellt, indem man ihr den Context der Java/Kotlin-Aktivität als Argument gibt.

Für ein Java-basiertes Projekt:

m_qtQuickView = new QtQuickView(this);

Für ein Kotlin-basiertes Projekt:

m_qtQuickView = QtQuickView(this)

Die Java-Klassen Main und Second erben von der Klasse QtQuickViewContent. Diese Klassen werden aus dem von uns importierten QML-Projekt generiert. In diesem Beispiel werden diese QML-Komponenten verwendet, um zu erklären, wie QML-Komponenten in Android-Projekte eingebettet werden können.

Für ein Java-basiertes Projekt:

private final Main m_mainQmlContent = new Main();
private final Second m_secondQmlContent = new Second();

Für ein Kotlin-basiertes Projekt (initialisiert beim Deklarieren):

private var m_mainQmlContent: Main = Main()
private val m_secondQmlContent: Second = Second()

Die m_mainQmlContent wird über die Methode QtQuickView.loadContent(), die QtQuickViewContent als Argument erhält, in die m_qtQuickView geladen.

Für ein Java-basiertes Projekt:

m_qtQuickView.loadContent(m_mainQmlContent);

Für ein Kotlin-basiertes Projekt:

m_qtQuickView!!.loadContent(m_mainQmlContent)

Die m_qtQuickView wird der Android FrameLayout ViewGroup mit den entsprechenden Layout-Parametern hinzugefügt.

Für ein Java-basiertes Projekt:

ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
m_qmlFrameLayout = findViewById(R.id.qmlFrame);
m_qmlFrameLayout.addView(m_qtQuickView, params);

Für ein Kotlin-basiertes Projekt:

val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
m_binding.qmlFrame.addView(m_qtQuickView, params)

Interaktion mit der QML-Komponente

Um mit der eingebetteten QML-Komponente zu interagieren, implementieren wir die Schnittstelle QtQmlStatusChangeListener und überschreiben die Methode onStatusChanged, um den Ladestatus des QtQuickViewContent zu erhalten, der gerade in m_qtQuickView geladen wird.

Für ein Java-basiertes Projekt:

public class MainActivity extends AppCompatActivity implements
QtQmlStatusChangeListener{
    ...
}

Für ein Kotlin-basiertes Projekt:

class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener{
    ...
}

Die onStatusChanged Implementierung.

Für ein Java-basiertes Projekt:

@Override
public void onStatusChanged(QtQmlStatus qtQmlStatus) {
    Log.i(TAG, "Status of QtQuickView: " + qtQmlStatus);

    final String qmlStatus = getResources().getString(R.string.qml_view_status)
            + m_statusNames.get(qtQmlStatus);

    // Show current QML View status in a textview
    m_qmlStatus.setText(qmlStatus);

    // Connect signal listener to "onClicked" signal from main.qml
    // addSignalListener returns int which can be used later to identify the listener
    if (qtQmlStatus == QtQmlStatus.READY && !m_switch.isChecked()) {
        m_qmlButtonSignalListenerId = m_mainQmlContent.connectOnClickedListener(
                (String name, Void v) -> {
                    Log.i(TAG, "QML button clicked");
                    m_androidControlsLayout.setBackgroundColor(Color.parseColor(
                            m_colors.getColor()
                    ));
                });

    }
}

Für ein Kotlin-basiertes Projekt:

override fun onStatusChanged(status: QtQmlStatus?) {
    Log.v(TAG, "Status of QtQuickView: $status")

    val qmlStatus = (resources.getString(R.string.qml_view_status)
            + m_statusNames[status])

    // Show current QML View status in a textview
    m_binding.qmlStatusText.text = qmlStatus

    // Connect signal listener to "onClicked" signal from main.qml
    // addSignalListener returns int which can be used later to identify the listener
    if (status == QtQmlStatus.READY && !m_binding.disconnectQmlListenerSwitch.isChecked) {
        m_qmlButtonSignalListenerId =
            m_mainQmlContent.connectOnClickedListener { _: String, _: Void? ->
                Log.i(TAG, "QML button clicked")
                m_binding.kotlinLinear.setBackgroundColor(
                    Color.parseColor(
                        m_colors.getColor()
                    )
                )
            }
    }
}

Der onStatusChanged Listener wird als statusChangeListener der m_mainQmlContent und m_secondQmlContent mit QtQuickViewContent.setStatusChangeListener(QtQmlStatusChangeListener onStatusChanged()) Methode eingestellt.

Für ein Java-basiertes Projekt:

m_mainQmlContent.setStatusChangeListener(this);
m_secondQmlContent.setStatusChangeListener(this);

Für ein Kotlin-basiertes Projekt:

m_mainQmlContent.setStatusChangeListener(this)
m_secondQmlContent.setStatusChangeListener(this)

Die überschriebene Callback-Funktion onStatusChanged() empfängt das Signal StatusChanged(), das den aktuellen Status (public Enum QtQmlStatus) des Ladens des aktuellen QtQuickViewContents in die m_qtQuickView enthält. Wenn diese QtQmlStatus als QtQmlStatus.READY bestätigt wird, können wir mit der QML-Ansicht interagieren.

Laden von QtQuickViewInhalten in QtQuickView

Sie können mehrere QtQuickViewContents im importierten QML-Projekt haben und den aktuell geladenen Inhalt des QtQuickViews zwischen ihnen wechseln, indem Sie die Methode QtQuickView.loadContent() verwenden, die einen QtQuickViewContent als Argument annimmt. Damit wird der angegebene QtQuickViewContent geladen und der vorherige entladen, falls vorhanden.

Für ein Java-basiertes Projekt:

private void loadSecondQml() {
    m_qtQuickView.loadContent(m_secondQmlContent);

    // Reset box color and color text after component reload
    m_box.setBackgroundColor(Color.parseColor("#00ffffff"));
    m_getPropertyValueText.setText("");
}

private void loadMainQml() {
    m_qtQuickView.loadContent(m_mainQmlContent);

    // Reset box color and color text after component reload
    m_box.setBackgroundColor(Color.parseColor("#00ffffff"));
    m_getPropertyValueText.setText("");
}

Für ein Kotlin-basiertes Projekt:

private fun loadSecondQml() {
    m_qtQuickView!!.loadContent(m_secondQmlContent)

    // Reset box color and color text after component reload
    m_binding.qmlColorBox.setBackgroundColor(Color.parseColor("#00ffffff"))
    m_binding.getPropertyValueText.text = ""
}

private fun loadMainQml() {
    m_qtQuickView!!.loadContent(m_mainQmlContent)

    // Reset box color and color text after component reload
    m_binding.qmlColorBox.setBackgroundColor(Color.parseColor("#00ffffff"))
    m_binding.getPropertyValueText.text = ""
}

Abrufen und Setzen von Eigenschaftswerten von QML-Komponenten

Das Abrufen und Setzen von Eigenschaftswerten von QML-Komponenten erfolgt über die in der Klasse Main.java beschriebenen Methoden. In diesem Fall verwenden wir die Methoden m_mainQmlContent.setColorStringProperty() und m_mainQmlContent.getColorStringProperty(). Diese Methoden werden je nachdem, welche Eigenschaften die QML-Komponente enthält, generiert.

Für ein Java-basiertes Projekt:

public void onClickListener() {
    // Set the QML view root object property "colorStringFormat" value to
    // color from Colors.getColor()
    m_mainQmlContent.setColorStringFormat(m_colors.getColor());

    String qmlBackgroundColor = m_mainQmlContent.getColorStringFormat();
    // Display the QML View background color code
    m_getPropertyValueText.setText(qmlBackgroundColor);

    // Display the QML View background color in a view
    // if qmlBackGroundColor is not null
    if (qmlBackgroundColor != null) {
        m_box.setBackgroundColor(Color.parseColor(qmlBackgroundColor));
    }
}

Für ein Kotlin-basiertes Projekt:

private fun onClickListener() {
    // Set the QML view root object property "colorStringFormat" value to
    // color from Colors.getColor()
    m_mainQmlContent.colorStringFormat = m_colors.getColor()

    val qmlBackgroundColor = m_mainQmlContent.colorStringFormat

    // Display the QML View background color code
    m_binding.getPropertyValueText.text = qmlBackgroundColor

    // Display the QML View background color in a view
    // if qmlBackgroundColor is not null
    if (qmlBackgroundColor != null) {
        m_binding.qmlColorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor))
    }
}

Mit der Methode m_mainQmlContent.setColorStringProperty() setzen wir den Eigenschaftswert colorStringFormat der Klasse m_mainQmlContent auf einen zufälligen Farbwert, der aus der Klasse Colors.java (oder Colors.kt) geholt wird.

Die Methode m_mainQmlContent.getColorStringProperty() wird hier verwendet, um die aktuelle Hintergrundfarbe des Root-Objekts des m_mainQmlContent zu holen und sie dann dem Benutzer auf der Java/Kotlin-Android-Seite der Anwendung anzuzeigen.

m_secondQmlContent hat eine Grid QML-Komponente, die wir von der Java-Seite mit der generierten m_secondQmlContent.setGridRotation() -Methode drehen können.

Für ein Java-basiertes Projekt:

private void rotateQmlGrid() {
    Integer previousGridRotation = m_secondQmlContent.getGridRotation();
    if (previousGridRotation != null) {
        m_secondQmlContent.setGridRotation(previousGridRotation + 45);
    }
}

Für ein Kotlin-basiertes Projekt:

private fun rotateQmlGrid() {
    val previousGridRotation = m_secondQmlContent.gridRotation
    if (previousGridRotation != null) {
        m_secondQmlContent.gridRotation = previousGridRotation + 45
    }
}

Signal-Listener

Die Klasse QtQuickViewContent bietet die Methoden connectSignalListener() und disconnectSignalListener(), die zum Verbinden und Trennen von Signalhörern zwischen Signalen, die im Stammobjekt der QML-Komponente deklariert sind, verwendet werden. QtQuickViewContent.connectSignalListener() gibt eine eindeutige Signal-Listener-ID zurück, die wir speichern und später verwenden, um den Listener zu identifizieren und die Verbindung zu trennen.

Hier verbinden wir einen Signal-Listener mit dem onClicked() Signal der QML-Komponente.

Für ein Java-basiertes Projekt:

if (qtQmlStatus == QtQmlStatus.READY && !m_switch.isChecked()) {
    m_qmlButtonSignalListenerId = m_mainQmlContent.connectOnClickedListener(
            (String name, Void v) -> {
                Log.i(TAG, "QML button clicked");
                m_androidControlsLayout.setBackgroundColor(Color.parseColor(
                        m_colors.getColor()
                ));
            });

}

Für ein Kotlin-basiertes Projekt:

if (status == QtQmlStatus.READY && !m_binding.disconnectQmlListenerSwitch.isChecked) {
    m_qmlButtonSignalListenerId =
        m_mainQmlContent.connectOnClickedListener { _: String, _: Void? ->
            Log.i(TAG, "QML button clicked")
            m_binding.kotlinLinear.setBackgroundColor(
                Color.parseColor(
                    m_colors.getColor()
                )
            )
        }
}

Das Signal onClicked() wird jedes Mal ausgegeben, wenn die Schaltfläche der QML-Komponente angeklickt wird. Dieses Signal wird dann von diesem Listener empfangen und die Hintergrundfarbe des Layouts, das die Android-Seite der Anwendung enthält, wird auf einen zufälligen Farbwert gesetzt, der aus der Klasse Colors.java abgerufen wird.

Als nächstes wird der Signal-Listener mit der Methode QtQuickViewContent.disconnectSignalListener() getrennt, indem ihm die eindeutige Signal-Listener-ID gegeben wird.

Für ein Java-basiertes Projekt:

m_mainQmlContent.disconnectSignalListener(m_qmlButtonSignalListenerId);

Für ein Kotlin-basiertes Projekt:

m_mainQmlContent.disconnectSignalListener(m_qmlButtonSignalListenerId)

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.