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

测试效果:

三、最后

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

相关推荐
YoungHong199211 分钟前
如何在 Android Framework层面控制高通(Qualcomm)芯片的 CPU 和 GPU。
android·cpu·gpu·芯片·高通
xzkyd outpaper15 分钟前
Android 事件分发机制深度解析
android·计算机八股
努力学习的小廉28 分钟前
深入了解linux系统—— System V之消息队列和信号量
android·linux·开发语言
cpp加油站1 小时前
Trae近期上新功能速览,国内版支持图片上传,新增进程资源管理器功能
ai编程·trae
cpp加油站1 小时前
我用Trae写了一个utools插件-灵感捕手,帮你捕捉转瞬即逝的灵感
ai编程·trae
程序员江同学1 小时前
Kotlin/Native 编译流程浅析
android·kotlin
移动开发者1号2 小时前
Kotlin协程与响应式编程深度对比
android·kotlin
钢铁男儿5 小时前
PyQt5高级界而控件(容器:装载更多的控件QDockWidget)
数据库·python·qt
花花鱼11 小时前
android studio 设置让开发更加的方便,比如可以查看变量的类型,参数的名称等等
android·ide·android studio