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
        }
    }
}

测试效果:

三、最后

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

相关推荐
demo007x15 小时前
万字长文解读ClaudeCode/KiloCode 文件处理技术
人工智能·claude·trae
雨白15 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk15 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING16 小时前
RN容器启动优化实践
android·react native
恋猫de小郭18 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack