Qt Quick 用于 Android Studio 项目

概述

本示例包含一个 QML 项目,您可以使用Qt Tools forAndroid Studio 插件将其导入 Android Studio,还包含通过使用QtQuickViewAPI 将 QML 项目用作视图的 Java 和 Kotlin 项目。

有关 QML 工作原理的更多信息,请参阅 Qt Qml.本文档将重点介绍如何将 QML 组件嵌入到基于 Java 和 Kotlin 的 Android 应用程序中。

首先,我们查看 Java 和 Kotlin 项目的MainActivity'onCreate() 方法。

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

    m_qmlViewBackgroundText = findViewById(R.id.qmlViewBackgroundText);
    m_qmlStatus = findViewById(R.id.qmlStatusText);
    m_androidControlsLayout = findViewById(R.id.javaRelative);
    m_colorBox = findViewById(R.id.qmlColorBox);
    m_switch = findViewById(R.id.disconnectQmlListenerSwitch);
    m_switch.setOnClickListener(view -> switchListener());
    QtQuickView m_firstQuickView = new QtQuickView(this);
    QtQuickView m_secondQuickView = new QtQuickView(this);

    // Set status change listener for m_qmlView
    // listener implemented below in OnStatusChanged
    m_firstQmlContent.setStatusChangeListener(this);
    m_secondQmlContent.setStatusChangeListener(this);
    final ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    FrameLayout m_firstQmlFrameLayout = findViewById(R.id.firstQmlFrame);
    m_firstQmlFrameLayout.addView(m_firstQuickView, params);
    FrameLayout m_secondQmlFrameLayout = findViewById(R.id.secondQmlFrame);
    m_secondQmlFrameLayout.addView(m_secondQuickView, params);
    m_firstQuickView.loadContent(m_firstQmlContent);
    m_secondQuickView.loadContent(m_secondQmlContent);

    Button m_changeColorButton = findViewById(R.id.changeQmlColorButton);
    m_changeColorButton.setOnClickListener(view -> onClickListener());
    Button m_rotateQmlGridButton = findViewById(R.id.rotateQmlGridButton);
    m_rotateQmlGridButton.setOnClickListener(view -> rotateQmlGrid());
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    m_binding = ActivityMainBinding.inflate(layoutInflater)
    val view = m_binding.root
    setContentView(view)

    m_binding.disconnectQmlListenerSwitch.setOnCheckedChangeListener { button, checked ->
        switchListener(
            button,
            checked
        )
    }

    val firstQtQuickView = QtQuickView(this)
    val secondQtQuickView = QtQuickView(this)

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

    val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
    )
    m_binding.firstQmlFrame.addView(firstQtQuickView, params)
    m_binding.secondQmlFrame.addView(secondQtQuickView, params)
    firstQtQuickView.loadContent(m_firstQmlContent)
    secondQtQuickView.loadContent(m_secondQmlContent)

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

注意: 在 Kotlin 项目中,我们使用视图绑定来访问应用程序的用户界面组件:

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

onCreate() 方法中,先前声明的变量将使用新的QtQuickViews 进行初始化。这些新的QtQuickView实例是通过将 Java/Kotlin Activity 的 Context 作为参数创建的。

Kotlin
QtQuickView m_firstQuickView = new QtQuickView(this);
QtQuickView m_secondQuickView = new QtQuickView(this);
val firstQtQuickView = QtQuickView(this)
val secondQtQuickView = QtQuickView(this)

QtQuickViews 通过适当的布局参数添加到 Android 布局中。

Kotlin
final ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout m_firstQmlFrameLayout = findViewById(R.id.firstQmlFrame);
m_firstQmlFrameLayout.addView(m_firstQuickView, params);
FrameLayout m_secondQmlFrameLayout = findViewById(R.id.secondQmlFrame);
m_secondQmlFrameLayout.addView(m_secondQuickView, params);
val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
m_binding.firstQmlFrame.addView(firstQtQuickView, params)
m_binding.secondQmlFrame.addView(secondQtQuickView, params)

MainSecond Java 类继承自QtQuickViewContent 类。这些类是从我们导入的 QML 项目中生成的。

Kotlin
private final Main m_firstQmlContent = new Main();
private final Second m_secondQmlContent = new Second();
private val m_firstQmlContent: Main = Main()
private val m_secondQmlContent: Second = Second()

Qt Quick 内容通过QtQuickView.loadContent() 方法加载,该方法将QtQuickViewContent 作为参数。

Kotlin
m_firstQuickView.loadContent(m_firstQmlContent);
m_secondQuickView.loadContent(m_secondQmlContent);
firstQtQuickView.loadContent(m_firstQmlContent)
secondQtQuickView.loadContent(m_secondQmlContent)

与 QML 组件交互

为了与嵌入式 QML 组件交互,我们实现了QtQmlStatusChangeListener 接口,并覆盖了 onStatusChanged 方法,以获取当前加载到 QtQuickViews 中的 QtQuickViewContent 的加载状态。

Kotlin
public class MainActivity extends AppCompatActivity implements
QtQmlStatusChangeListener {
    ...
}
class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener {
    ...
}

onStatusChanged 实现:

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

    // Show current QML View status in a textview
    m_qmlStatus.setText(getString(R.string.qml_view_status, m_statusNames.get(qtQmlStatus)));
    updateColorDisplay();

    if (content == m_firstQmlContent) {
        // 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_firstQmlContent.connectOnClickedListener(
                    (String name, Void v) -> {
                        Log.i(TAG, "QML button clicked");
                        m_androidControlsLayout.setBackgroundColor(Color.parseColor(
                                m_colors.getColor()
                        ));
                    });
        }
    }
}
override fun onStatusChanged(status: QtQmlStatus?, content: QtQuickViewContent?) {
    Log.v(TAG, "Status of QtQuickView: $status")

    // Show current QML View status in a textview
    m_binding.qmlStatusText.text = getString(R.string.qml_view_status, m_statusNames[status])

    updateColorDisplay()

    if (content == m_firstQmlContent) {
        // 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_firstQmlContent.connectOnClickedListener { _: String, _: Void? ->
                    Log.i(TAG, "QML button clicked")
                    m_binding.kotlinRelative.setBackgroundColor(
                        Color.parseColor(
                            m_colors.getColor()
                        )
                    )
                }
        }
    }
}

MainActivity 通过QtQuickViewContent.setStatusChangeListener 方法设置为m_mainQmlContentm_secondQmlContentstatusChangeListener

Kotlin
m_firstQmlContent.setStatusChangeListener(this);
m_secondQmlContent.setStatusChangeListener(this);
m_firstQmlContent.setStatusChangeListener(this)
m_secondQmlContent.setStatusChangeListener(this)

重载的回调函数onStatusChanged() 接收StatusChanged() 信号,其中包含将当前QtQuickViewContent 加载到QtQuickView 的当前状态(公共枚举 QtQmlStatus)。如果该QtQmlStatus 被确认为QtQmlStatus.READY ,我们就可以开始与 QML 视图交互了。

获取和设置 QML 组件属性值

获取和设置 QML 组件属性值通过Main.java 类中描述的方法进行。在这种情况下,我们使用m_mainQmlContent.setColorStringProperty()m_mainQmlContent.getColorStringProperty() 方法。这些方法是根据 QML 组件包含的属性生成的。

Kotlin
public void onClickListener() {
    // Set the QML view root object property "colorStringFormat" value to
    // color from Colors.getColor()
    m_firstQmlContent.setColorStringFormat(m_colors.getColor());
    updateColorDisplay();
}
private void updateColorDisplay() {
    String qmlBackgroundColor = m_firstQmlContent.getColorStringFormat();
    // Display the QML View background color code
    m_qmlViewBackgroundText.setText(qmlBackgroundColor);

    // Display the QML View background color in a view
    // if qmlBackGroundColor is not null
    if (qmlBackgroundColor != null) {
        m_colorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor));
    }
}
private fun onClickListener() {
    // Set the QML view root object property "colorStringFormat" value to
    // color from Colors.getColor()
    m_firstQmlContent.colorStringFormat = m_colors.getColor()
    updateColorDisplay()
}

private fun updateColorDisplay() {
    val qmlBackgroundColor = m_firstQmlContent.colorStringFormat
    // Display the QML View background color code
    m_binding.qmlViewBackgroundText.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))
    }
}

通过m_mainQmlContent.setColorStringProperty() 方法,我们将m_mainQmlContentcolorStringFormat 属性值设置为从Colors.java (或Colors.kt )类中获取的随机颜色值。

m_mainQmlContent.getColorStringProperty() 方法用于获取 m_mainQmlContent 根对象的当前背景颜色,然后在应用程序的 Java/Kotlin Android 端向用户显示。

m_secondQmlContent m_mainQmlContent 有一个 QML 组件,我们可以使用生成的 方法从 Java 端旋转该组件。Grid m_secondQmlContent.setGridRotation()

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

信号侦听器

QtQuickViewContent 类提供connectSignalListener()disconnectSignalListener() 方法,用于连接和断开 QML 组件根对象中声明的信号之间的信号监听器。QtQuickViewContent.connectSignalListener() 返回一个唯一的信号监听器 id,我们将其存储起来,以后用来识别和断开监听器。

在这里,我们将信号监听器连接到 QML 组件的onClicked() 信号。

Kotlin
if (qtQmlStatus == QtQmlStatus.READY && m_switch.isChecked()) {
    m_qmlButtonSignalListenerId = m_firstQmlContent.connectOnClickedListener(
            (String name, Void v) -> {
                Log.i(TAG, "QML button clicked");
                m_androidControlsLayout.setBackgroundColor(Color.parseColor(
                        m_colors.getColor()
                ));
            });
}
if (status == QtQmlStatus.READY && m_binding.disconnectQmlListenerSwitch.isChecked) {
    m_qmlButtonSignalListenerId =
        m_firstQmlContent.connectOnClickedListener { _: String, _: Void? ->
            Log.i(TAG, "QML button clicked")
            m_binding.kotlinRelative.setBackgroundColor(
                Color.parseColor(
                    m_colors.getColor()
                )
            )
        }
}

每次点击 QML 组件上的按钮时,都会发出onClicked() 信号。该监听器接收到该信号后,应用程序 Android 端布局的背景颜色就会设置为从Colors.java 类中获取的随机颜色值。

接下来,使用QtQuickViewContent.disconnectSignalListener() 方法断开信号监听器的连接,为其提供唯一的信号监听器 ID。

Kotlin
m_firstQmlContent.disconnectSignalListener(m_qmlButtonSignalListenerId);
m_firstQmlContent.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.