Android Studio 项目中的 QML

概览

本示例包含一个可导入到 Android Studio 的 QML 项目,您可以使用 Qt Tools for Android Studio 插件将其导入,并使用 Java 和 Kotlin 项目,这些项目利用了 QtQuickView API。

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

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

对于基于 Java 的项目

@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.qmlStatus);
    m_androidControlsLayout = findViewById(R.id.javaLinear);
    m_box = findViewById(R.id.box);

    m_switch = findViewById(R.id.switch1);
    m_switch.setOnClickListener(view -> switchListener());
    m_qmlView = new QtQuickView(this, "qrc:/qt/qml/qml_in_android_view/main.qml",
            "qml_in_android_view");

    // Set status change listener for m_qmlView
    // listener implemented below in OnStatusChanged
    m_qmlView.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_qmlView, params);
    Button button = findViewById(R.id.button);
    button.setOnClickListener(view -> onClickListener());

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

对于基于 Kotlin 的项目

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

    m_binding.signalSwitch.setOnClickListener { switchListener() }

    m_qmlView = QtQuickView(
        this, "qrc:/qt/qml/qml_in_android_view/main.qml",
        "qml_in_android_view"
    )

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

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

    m_binding.changeColorButton.setOnClickListener { onClickListener() }

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

注意:在 Kotlin 项目中,我们使用 View binding 来访问应用程序的 UI 组件

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

onCreate() 方法内,通过给 QtQuickView 参数提供 Java/Kotlin 应用程序 Context、QML 项目 main.qml 文件的 URI 以及 QML 项目的库名作为参数,创建了一个名为 m_qmlViewQtQuickView 实例。

对于基于 Java 的项目

m_qmlView = new QtQuickView(this, "qrc:/qt/qml/qml_in_android_view/main.qml",
        "qml_in_android_view");

对于基于 Kotlin 的项目

m_qmlView = QtQuickView(
    this, "qrc:/qt/qml/qml_in_android_view/main.qml",
    "qml_in_android_view"
)

m_qmlView 然后被添加到具有适当布局参数的 Android FrameLayout ViewGroup 中。

对于基于 Java 的项目

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

对于基于 Kotlin 的项目

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

与 QML 组件交互

为了与嵌入的 QML 组件进行交互,我们首先需要实现 QtQuickView 的公共接口 StatusChangeListener

对于基于 Java 的项目

public class MainActivity extends AppCompatActivity implements
QtQuickView.StatusChangeListener{
    ...
}

对于基于 Kotlin 的项目

class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener{
    ...
}

然后,定义一个对 StatusChangeListener 回调函数 onStatusChanged() 的重写。

对于基于 Java 的项目

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

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

    // 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 (status == QtQuickView.STATUS_READY && !m_switch.isChecked()) {
        m_qmlButtonSignalListenerId = m_qmlView.connectSignalListener("onClicked", Object.class,
                (String signal, Object o) -> {
            Log.i(TAG, "QML button clicked");
            m_androidControlsLayout.setBackgroundColor(Color.parseColor(m_colors.getColor()));
        });

    }
}

对于基于 Kotlin 的项目

override fun onStatusChanged(status: Int) {
    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.qmlStatus.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 == QtQuickView.STATUS_READY && !m_binding.signalSwitch.isChecked) {
        m_qmlButtonSignalListenerId = m_qmlView!!.connectSignalListener(
            "onClicked", Any::class.java
        ) { _: String?, _: Any? ->
            Log.v(TAG, "QML button clicked")
            m_binding.kotlinLinear.setBackgroundColor(Color.parseColor(m_colors.getColor()))
        }
    }
}

然后,使用 setStatusChangeListener() 将该监听器设为监听 m_qmlView 的状态变化。

对于基于 Java 的项目

m_qmlView.setStatusChangeListener(this);

对于基于 Kotlin 的项目

m_qmlView!!.setStatusChangeListener(this)

重写的回调函数 onStatusChanged() 接收包含当前 m_qmlView状态值StatusChanged() 信号。如果这个 状态值 被确认是 STATUS_READY,我们就可以开始与 QML 视图进行交互了。

获取和设置 QML 视图属性值

获取和设置 QML 视图属性值是通过 QtQuickView.getProperty()QtQuickView.setProperty() 方法来完成的。

当 Android 按钮的点击事件发生时,设置了 QML 组件背景颜色的根对象。

对于基于 Java 的项目

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

    String qmlBackgroundColor = m_qmlView.getProperty("colorStringFormat");

    // Display the QML View background color code
    m_getPropertyValueText.setText(qmlBackgroundColor);

    // Display the QML View background color in a view
    m_box.setBackgroundColor(Color.parseColor(qmlBackgroundColor));
}

对于基于 Kotlin 的项目

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

    val qmlBackgroundColor = m_qmlView!!.getProperty<String>("colorStringFormat")

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

    // Display the QML View background color in a view
    m_binding.colorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor))
}

使用 QtQuickView.setProperty() 方法,我们将 "colorStringFormat" 属性值设置为从项目的 Colors.java 类中获取的随机颜色值。

此处使用 QtQuickView.getProperty(){QtQuickView.getProperty()} 方法来获取 QML 组件根对象的当前背景颜色,并在应用的 Android 端显示。

信号监听器

QtQuickView 类提供了 connectSignalListener()disconnectSignalListener() 方法,用于连接和断开信号监听器到 QML 组件根对象中声明的信号。

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

对于基于 Java 的项目

if (status == QtQuickView.STATUS_READY && !m_switch.isChecked()) {
    m_qmlButtonSignalListenerId = m_qmlView.connectSignalListener("onClicked", Object.class,
            (String signal, Object o) -> {
        Log.i(TAG, "QML button clicked");
        m_androidControlsLayout.setBackgroundColor(Color.parseColor(m_colors.getColor()));
    });

}

对于基于 Kotlin 的项目

if (status == QtQuickView.STATUS_READY && !m_binding.signalSwitch.isChecked) {
    m_qmlButtonSignalListenerId = m_qmlView!!.connectSignalListener(
        "onClicked", Any::class.java
    ) { _: String?, _: Any? ->
        Log.v(TAG, "QML button clicked")
        m_binding.kotlinLinear.setBackgroundColor(Color.parseColor(m_colors.getColor()))
    }
}

onClicked() 信号在 QML UI 中的按钮每次被点击时都会发出。该信号随后被此监听器接收,并将持有应用 Android 端的布局的背景颜色设置为从项目的 Colors.java 类中获取的随机颜色值。

QtQuickView.connectSignalListener() 返回一个唯一的信号监听器 ID,我们将其存储并用于后来的标识和断开监听器。

对于基于 Java 的项目

m_qmlView.disconnectSignalListener(m_qmlButtonSignalListenerId);

对于基于 Kotlin 的项目

m_qmlView!!.disconnectSignalListener(m_qmlButtonSignalListenerId)

在此,我们使用 QtQuickView.disconnectSignalListener() 方法通过提供一个唯一的信号监听器 ID 来断开之前连接的信号监听器。

© 2024 The Qt Company Ltd. 本文档中包含的贡献的文档版权为各自所有者的版权。本提供的文档是根据自由软件基金会发布的 GNU 自由文档许可版 1.3 的条款许可的。Qt 及其相关标志是 The Qt Company Ltd. 在芬兰和/或其他国家的商标。所有其他商标均为各自所有者的财产。