Qt Android开发问题汇总

2023-05-16

Qt Android开发问题汇总

  • 摘要
  • 1.Qt Quick编写Android应用,使状态栏颜色和应用保持一致
    • 总结

摘要

作为一名工作中使用Qt的开发者,主要做的是桌面应用开发。开发Android应用主要是想要尝试移动端开发一些简单、练习性质的应用。使用Qt Quick开发时只是大致看了Android官方文档的基础内容部分,并没有足够的Android知识储备。所以在这个过程中可能会遇到比较多的问题。

为了避免自己以后重复遇到类似问题,或者你也正遇到类似问题而正在网络上到处搜索和尝试解决方案,我在此做个记录分享给有需要的各位。

以后遇到凡涉及Qt Android开发的相关问题,都会在这里更新。

1.Qt Quick编写Android应用,使状态栏颜色和应用保持一致

整体实现过程是:

  • 启动时在Android Java中设置状态栏为透明、应用全屏显示
  • Android端获取并存储状态栏高度
  • Qt端根据需要设置状态栏位置处QML组件的颜色

为了便于演示,我先建立了一个示例Qt Quick工程:
新建Qt Quick项目
创建Android工程模板文件:
build settings

在文件浏览器中找到 AndroidManifest.xml 文件,然后使用其他编辑器打开:
在这里插入图片描述
找到<activity>标签的android:name属性,其默认值为:org.qtproject.qt5.android.bindings.QtActivity

Activity类是android中的主要组件之一,用来显示界面。在AndroidManifest.xml中定义的<activity>就表示了一个该组件。其android:name属性则指向了派生自Activity类的子类。所以org.qtproject.qt5.android.bindings.QtActivity就表示这是Qt中实现的Activity子类。它实现了加载和显示Qt Quick绘制界面的组件等功能。

在原生Android开发中,不同页面会定义不同的Activity。但使用Qt Quick, Flutter等采用Direct UI方式实现的第三方开发框架则只定义了一个Activity。里面不同页面实际都是使用OpenGL等直接绘制的。

回到正题,我们需要创建新的java源文件,然后自己定义一个 activity,但它不是继承Activiy,而是继承org.qtproject.qt5.android.bindings.QtActivity
在这里插入图片描述
然后将android:name属性指向这个类:
在这里插入图片描述
最后的重点来了,我们需要在自定义的 activity启动时设置相应属性,并获取到状态栏高度:

// me/quick/app/SameStatusBarActivity.java

package me.quick.app;

import android.content.Context;
import android.os.Bundle;
import android.os.Build;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.app.ActionBar;
import android.app.Application;
import android.content.res.Resources;

public class SameStatusBarActivity extends org.qtproject.qt5.android.bindings.QtActivity {
    public SameStatusBarActivity() { }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                       | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                       | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
            decorView.setSystemUiVisibility(option);

            //透明状态栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //透明导航栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            // getWindow().getDecorView().setFitsSystemWindows(true);
        }
        // ActionBar actionBar = getActionBar();
        // actionBar.hide();
        // 获取并保存状态栏高度
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen","android");
        if (resourceId > 0) {
            statusHeight = getResources().getDimensionPixelSize(resourceId);
        } else {
            statusHeight = 48;
        }
    }

    private static int statusHeight;
    // 该接口在Qt C++中调用
    public static int getStatusBarHeight() {
        return statusHeight;
    }
}

然后在Qt中定义一个新的继承自QObject的类,我将其取名为AndroidHelper

#include <QObject>

class AndroidHelper : public QObject
{
    Q_OBJECT

    Q_PROPERTY(int androidStatusBarHeight READ androidStatusBarHeight)
public:
    explicit AndroidHelper(QObject *parent = nullptr);

    int androidStatusBarHeight();
private:
    int mAStatusBarHeight {0};
};

我们在AndroidHelper::androidStatusBarHeight调用之前定义的java类SameStatusBarActivity的类静态方法getStatusBarHeight

int AndroidHelper::androidStatusBarHeight()
{
    if (mAStatusBarHeight == 0) {
        mAStatusBarHeight = QAndroidJniObject::callStaticMethod<int>(
                                "me/quick/app/SameStatusBarActivity",
                                "getStatusBarHeight"
                            );
    }

    return mAStatusBarHeight;
}

main.cpp文件中,我们创建一个AndroidHelper对象,并将其设置为属性,以便在QML中使用:

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    // **
    AndroidHelper *helper = new AndroidHelper(&engine);
    engine.rootContext()->setContextProperty("AndroidHelper", helper);
    // **

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

最后就可以在QML中调用AndroidHelper.androidStatusBarHeight获取状态栏高度了。

这里,我们在QML中定义一个ToolBar,它将包括Android StatusBar的部分,使其背景和应用ToolBar保持一致。

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.Material 2.12

ApplicationWindow {
    id: _win
    visible: true
    width: 640
    height: 480

    header: ToolBar {
        ColumnLayout {
            anchors.fill: parent
            spacing: 0

            Rectangle {
                Layout.fillWidth: true
                height: AndroidHelper.androidStatusBarHeight * 0.35
                color: Material.primary
            }
            RowLayout {
                Layout.fillWidth: true
                Layout.fillHeight: true
                ToolButton {
                    text: 'Ok'
                    onClicked: _drawer.open()
                }
            }
        }
    }

    Text {
        anchors.centerIn: parent
        font.bold: true
        font.pointSize: 48
        text: AndroidHelper.androidStatusBarHeight
    }

    Drawer {
        id: _drawer
        edge: Qt.LeftEdge
        width: _win.width * 0.7
        height: _win.height

        Pane {
            anchors.fill: parent
            Text {
                anchors.centerIn: parent
                text: 'Drawer'
                font.bold: true
                font.pointSize: 48
            }
        }
    }
}

在上面的QML代码中,我为header属性定义了ToolBar组件,内部使用ColumnLayout布局,第一个子组件使用了一个Rectangle,让其作为Android StatusBar的背景区域。

为了使应用使用Google Material界面风格,还需要定义一个qtquickcontrols2.conf文件:

[Controls]
Style=Material

[Material]
Theme=Light

然后在QML将StatusBar区域的Rectangle颜色设置为Material.primary,这和ToolBar的颜色一致。

最终效果如下:
在这里插入图片描述在这里插入图片描述

总结

此处使用的方法,存在一个问题:从android java中获取的StatusBar高度值,不能直接在QML中作为高度值设置,需要乘个系数去和真实高度做大致匹配。在不同设备中这个系数也不一定一致。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt Android开发问题汇总 的相关文章

  • PDF文件中电子签名(安全性、有效性、合法性)验证指南

    电子合同是电子签名较为常见的一种应用方式 xff0c 目前大多数的的电子合同与电子文书都采用PDF的文件格式 本文以PDF格式的电子合同为例解释如何验证电子签名的安全性 有效性与合法性 xff08 下文统称 验签 xff09 xff0c 同
  • 数据结构专题——二叉树

    什么是二叉树 通俗的讲就是树上每一个节点最多有两个子节点 官方的递归定义是 xff1a 要么二叉树没有根节点 xff0c 是一颗空树要么二叉树由根结点 左子树 右子树组成 xff0c 且左右子树也都是二叉树 这里有两种特殊的二叉树 满二叉树
  • CSS filter滤镜属性使用

    前言 CSS的滤镜filter属性 xff0c 可以对网页中的图片进行类似Photoshop图片处理的效果 xff0c 通过CSS对图像进行处理 xff0c CSS的filter属性可以得到一些类似PS的滤镜效果 浏览器支持情况 xff1a
  • vtk中的剪裁

    在VTK中 xff0c 我们通常需要的并不是严格标准的几何体 xff0c 我们需要对这些几何体进行加工 xff0c 修改其内容 xff0c 得到我们想要的效果 xff0c 下面结合例子介绍如何在VTK中实现对几何体的裁剪 要对几何体进行裁剪
  • Ubuntu18.04搭建jenkins,并关联Github

    一 Ubuntu搭建jenkins 1 安装Java环境 sudo apt install openjdk 11 jre headless 创建一个Jenkins目录 xff0c 并进入 mkdir Jenkins cd Jenkins 3
  • 使用FOFA进行资产收集

    使用FOFA进行资产收集 FOFA是一款空间搜索引擎 它可以通过进行网络空间测绘快速进行网络资产匹配FOFA官方地址 https fofa so 我们使用FOFA进行搜索资产的时候他是不区分大小写的 xff1b 并且我们可以使用一些逻辑连接
  • python针对文本的操作

    Python文件的处理 1 我们可以把文件想象成一个仓库 xff1b 可以供我们操作使用 针对文件的操作流程为 xff1a 打开文件并且创建对象 xff1b 对该文件内容进行 读取 写入 删除 修改等操作 关闭并且保存 2 常用操作函数 o
  • 【CVE-2016-3088】 Activemq文件上传以及弱口令

    CVE 2016 3088 PUT方法上传文件 自建环境 漏洞描述 Apache ActiveMQ是美国阿帕奇 xff08 Apache xff09 软件基金会的一套开源的消息中间件 Apache ActiveMQ 5 14 0之前5 x版
  • Apache SSI 远程命令执行漏洞

    apache ssi 文件上传导致的命令执行 漏洞描述 如果目标服务器开启了SSI与CGI支持 这样我们就可以上传一个可执行的shtml文件 漏洞复现过程 1 访问文件上传页面进行上传可执行文件shtml文件 2 访问我们上传成功的shtm
  • Linux周期计划及开启自启动

    Linux 周期计划 linux的周期计划是由crond服务控制 systemctl status crond 进行查看服务运行状态 Linux 周期计划可分 系统性周期计划 用户周期性计划 系统性周期计划 xff1a etc cronta
  • Tableau实现增量刷新

    为了节省tableau的刷新时间 xff0c 有时候我们只需要增量刷新就可以了 xff0c 设置如下图 选择菜单栏的 数据 提取刷新 所有行 增量刷新 xff0c 然后再选择对应的增量标识符就可以了 xff0c 比如我选择的是日期 DOB
  • 潘多拉盒子 使用 hd-idle 硬盘休眠设置

    潘多拉盒子 使用 hd idle 硬盘休眠设置 潘多拉或OpenWrt路由器你去 挂载点 那里去看路径 比如你挂载的是 dev sda5 xff08 1 2 3 5看自己路由器挂载硬盘的情况 xff09 路径 xff0c 那么硬盘休眠就写这
  • nigix代理失败的排查过程

    背景 在刚开始迁移的过程中 xff0c 由于经常进 部署实验 xff0c 需要 便进 dns解析更换IP的操作 xff0c 在预发布域名解析中申请了七层负载均衡的vip xff0c 通过vip来调整具体的解析ip 问题 这时问题就发 了 x
  • 计数排序算法优化,增加对负数及小数的支持

    计数排序算法优化 1 增加对负数及小数的支持 2 当数列最大最小值差距过大时 xff0c 其空间复杂度超过NlogN时 采用时间复杂度小于等于NlogN的排序算法 优化后的计算排序算法 xff1a 经过改进后的计数排序 xff0c 不在局限
  • win10下使用Rclone将OneDrive映射到本地磁盘教程(开机自动挂载)

    win10下使用Rclone将OneDrive映射到本地磁盘教程 xff08 开机自动挂载 xff09 下载rclone xff0c winfsp和Git bashRclone Winfsp 和 Git bash https gitforw
  • 基于ROS的机器人模型建立及3D仿真【物理/机械意义】

    前言 在前面的博客中 xff0c 我们已经学习过了如何对目标机器人进行数学意义上的模型建立 xff0c 以便实现基础控制 xff0c 而在实际生活中 xff0c 由于机器人造价高昂 xff0c 我们往往难以获得实际的目标机器人进行部署研究
  • 【ROS进阶篇】第八讲(上) URDF文件的语法详解

    ROS进阶篇 第八讲 xff08 上 xff09 URDF文件的语法详解 文章目录 ROS进阶篇 第八讲 xff08 上 xff09 URDF文件的语法详解前言一 URDF的基本概念二 link标签1 标签作用2 子标签 三 joint标签
  • 【基于ROS的URDF练习实例】四轮机器人与摄像头的使用

    前言 在上一节博客中我们系统的学习了关于URDF的基本使用语法 xff0c 并从标签 属性 结构关系等多个方面深入体会了URDF文件的框架和理念 xff0c 本篇文章则主要针对于实际的仿真开发 xff0c 分别从带有摄像头的长方体和四轮圆柱
  • 【ROS进阶篇】第八讲(下) URDF的编程优化Xacro使用

    ROS进阶篇 第八讲 xff08 下 xff09 URDF的编程优化Xacro使用 文章目录 ROS进阶篇 第八讲 xff08 下 xff09 URDF的编程优化Xacro使用前言一 Xacro的基本概念二 Xacro的语法详解三 实际机器
  • 【ROS进阶篇】第九讲 基于Rviz和Arbotix控制的机器人模型运动

    ROS进阶篇 第九讲 基于Rviz和Arbotix控制的机器人模型运动 文章目录 ROS进阶篇 第九讲 基于Rviz和Arbotix控制的机器人模型运动前言一 Arbotix功能包介绍1 基本简介 xff1a 2 安装教程 xff1a 二

随机推荐