MacOS下Qt+qml+Android开发系列:2、切换页面

一、前言

上次了解了使用qml实现常见的一些控件,在设备上也做了测试,基本的简单页面已经可以开发出来了,但是实际使用中都是多个页面的,多个页面的切换也是必不可少的,这一次我们就再问一下trae如何进行qml的多页面开发,而且多个页面我们也通过多个qml文件来区分,保证可复用性。

二、qml常见页面切换方式

直接问trae:

在你的项目中,我建议使用 StackView 方式,因为它:

  1. 有完整的页面栈管理
  2. 支持前进/后退动画
  3. 内存管理更高效
  4. 与你的现有项目结构兼容性好

需要特别注意:

  1. 每个页面最好封装为单独的 Component 或 QML 文件
  2. 页面切换时要处理好数据传递
  3. 安卓/iOS 上有原生风格的过渡动画可用

在 QML 中,常见的页面切换方式有以下几种,我将结合你的当前项目结构为你详细介绍:

1. 使用 StackView(推荐方式)

StackView 是最常用的页面管理组件,适合大多数应用场景。

plain 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    // ... existing code ...
    
    StackView {
        id: stackView
        anchors.fill: parent
        initialItem: Page1 {}
    }

    Component {
        id: page1
        Rectangle {
            color: "lightblue"
            Button {
                text: "去第二页"
                onClicked: stackView.push(page2)
            }
        }
    }

    Component {
        id: page2
        Rectangle {
            color: "lightgreen"
            Button {
                text: "返回"
                onClicked: stackView.pop()
            }
        }
    }
}

测试代码:

我们创建包括main.qml的三个qml文件:main.qml、home.qml、login.qml,main.qml用于控制切换,login.qml设计为登录页面,home.qml为进入后的主页,默认显示登录页面,点击登录按钮后进入home页面,点击home页面的返回则退出到登录页面。

javascript 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    width: 720
    height: 1440
    visible: true
    title: qsTr("登录应用")

    StackView {
        id: stackView
        anchors.fill: parent
        initialItem: Qt.createComponent("login.qml").createObject(stackView, {"stackView": stackView})
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
    id: loginPage
    property var stackView
    width: parent.width
    height: parent.height

    Column {
        anchors.centerIn: parent
        spacing: 20

        Label {
            text: "登录页面"
            font.pixelSize: 24
        }

        Button {
            text: "登录"
            onClicked: stackView.push(Qt.resolvedUrl("home.qml"), {"stackView": stackView})
        }
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
    id: homePage
    property var stackView
    width: parent.width
    height: parent.height
    color: "lightgreen"
    
    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "欢迎来到主页"
            font.pixelSize: 24
        }
        
        Button {
            text: "返回登录页"
            onClicked: stackView.pop()
        }
    }
}

测试效果:

2. 使用 Loader 动态加载

适合需要频繁切换但不需要保留页面状态的场景。

plain 复制代码
// ... existing code ...
Loader {
    id: pageLoader
    anchors.fill: parent
    sourceComponent: page1
}

Button {
    text: "切换页面"
    onClicked: pageLoader.sourceComponent = 
        (pageLoader.sourceComponent == page1) ? page2 : page1
}
// ... existing code ...

测试代码:

也是三个qml文件,这种方式感觉简单很多,但是没有切换页面的效果:

javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Window {
    width: 720
    height: 1440
    visible: true
    title: qsTr("Loader示例")

    property string currentPage: "login.qml"

    Loader {
        id: pageLoader
        anchors.fill: parent
        source: currentPage
    }

    Connections {
        target: pageLoader.item
        ignoreUnknownSignals: true
        function onChangePage(page) {
            currentPage = page
        }
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Item {
    signal changePage(string page)

    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "登录页面"
            font.pixelSize: 24
        }
        
        Button {
            text: "登录"
            onClicked: changePage("home.qml")
        }
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Item {
    signal changePage(string page)

    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "欢迎来到主页"
            font.pixelSize: 24
        }
        
        Button {
            text: "返回登录页"
            onClicked: changePage("login.qml")
        }
    }
}

测试效果:

3. 使用 SwipeView

适合需要左右滑动切换页面的场景。

plain 复制代码
// ... existing code ...
import QtQuick.Controls 2.12

SwipeView {
    id: swipeView
    anchors.fill: parent
    
    Page1 {}
    Page2 {}
    Page3 {}
}

PageIndicator {
    anchors.bottom: parent.bottom
    currentIndex: swipeView.currentIndex
    count: swipeView.count
}
// ... existing code ...

测试代码:

这种也是三个文件,用户左右滑动进行页面切换,很多app都是这种切换方式:

javascript 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    width: 720
    height: 1440
    visible: true
    title: qsTr("滑动视图示例")

    SwipeView {
        id: swipeView
        anchors.fill: parent
        currentIndex: 0
        interactive: true

        Loader {
            source: "login.qml"
        }

        Loader {
            source: "home.qml"
        }
    }

    PageIndicator {
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        count: swipeView.count
        currentIndex: swipeView.currentIndex
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
    width: parent.width
    height: parent.height
    
    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "登录页面"
            font.pixelSize: 24
        }
        
        Button {
            text: "滑动到主页"
            onClicked: swipeView.currentIndex = 1
        }
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Rectangle {
    width: parent.width
    height: parent.height
    
    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "欢迎来到主页"
            font.pixelSize: 24
        }
        
        Button {
            text: "滑动回登录页"
            onClicked: swipeView.currentIndex = 0
        }
    }
}

测试效果:

4. 使用 TabBar + StackLayout

适合需要标签页导航的场景。

plain 复制代码
// ... existing code ...
TabBar {
    id: tabBar
    TabButton { text: "首页" }
    TabButton { text: "设置" }
}

StackLayout {
    currentIndex: tabBar.currentIndex
    Page1 {}
    Page2 {}
}
// ... existing code ...

测试代码:

也是分为三个页面,这种方式也是用的比较多的:

javascript 复制代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12

Window {
    width: 720
    height: 1440
    visible: true
    title: qsTr("底部标签栏示例")

    // 主布局容器
    Column {
        anchors.fill: parent

        StackLayout {
            id: stackLayout
            width: parent.width
            height: parent.height - tabBar.height
            currentIndex: tabBar.currentIndex

            // 登录页面
            Loader {
                source: "login.qml"
            }

            // 主页
            Loader {
                source: "home.qml"
            }
        }

        // 底部标签栏
        TabBar {
            id: tabBar
            width: parent.width
            position: TabBar.Footer
            currentIndex: 0

            TabButton {
                text: qsTr("登录")
            }

            TabButton {
                text: qsTr("主页")
            }
        }
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Item {
    width: parent.width
    height: parent.height
    
    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "登录页面"
            font.pixelSize: 24
        }
        
        Button {
            text: "滑动到主页"
            onClicked: swipeView.currentIndex = 1
        }
    }
}
javascript 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12

Item {
    width: parent.width
    height: parent.height
    
    Column {
        anchors.centerIn: parent
        spacing: 20
        
        Label {
            text: "欢迎来到主页"
            font.pixelSize: 24
        }
        
        Button {
            text: "滑动回登录页"
            onClicked: swipeView.currentIndex = 0
        }
    }
}

测试效果:

三、最后

这些页面切换方式其实没有绝对的好坏,主要还是要分场景去使用的。

相关推荐
FEF前端团队1 小时前
AI 编程 Agent 全景解读:从 Chat 到 Agent,你的代码助手进化到了哪一步?
ai编程·cursor·trae
刮风那天1 小时前
Android 如何降低进程优先级可以被查杀?
android
_風箏2 小时前
TRAE SOLO 移动版的安装与测试
trae
程序leo源2 小时前
Qt信号与槽深度详解
c语言·开发语言·数据库·c++·qt·c#
资源分享助手2 小时前
超级改图P图改字无限制版教程(安卓)AI改图软件、图片改字软件、安卓修图APP、智能消除工具、图片拼接APP、超级改图下载
android·人工智能
Lehjy3 小时前
【Linux】文件系统磁盘存储结构
android·linux·运维
yu85939583 小时前
基于 QT5.7.0 的八线激光雷达点云聚类实现
开发语言·qt·聚类
BU摆烂会噶3 小时前
【LangGraph】节点内调用与状态隔离
android·人工智能·python·ui·langchain·人机交互
努力努力再努力wz4 小时前
【C++高阶数据结构系列】:时间轮定时器详解:原理分析与代码实现,带你从零手撕时间轮!(附时间轮的实现源码)
c语言·开发语言·数据结构·c++·qt·算法·ui
郝学胜-神的一滴4 小时前
Qt 高级开发 006: 架构全解 + 高效学习指南
开发语言·c++·qt·程序人生·架构