QML Flipable:卡片翻转与登录设置

Flipable 是 Qt Quick 里一种可翻转的组件,一个物体有两面,配合旋转变换和动画,就能像扑克牌一样翻过去。这篇文章先用一张扑克牌展示它是如何翻转的,再把它应用到实际场景中展示如何切换设置、登录页面。

Flipable 翻转卡片

一张扑克牌,点击后绕竖轴翻转 180°,露出背面。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Layouts

FadeInAnimation {

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        Flipable {
            id: flipable
            Layout.fillWidth: true
            Layout.fillHeight: true

            property bool flipped: false

            front: Image {
                anchors.fill: parent
                source: "qrc:/images/SpadeA.png"
                fillMode: Image.PreserveAspectFit
                smooth: true
            }

            back: Image {
                anchors.fill: parent
                source: "qrc:/images/Background.png"
                fillMode: Image.PreserveAspectFit
                smooth: true
            }

            transform: Rotation {
                id: rotation
                origin.x: flipable.width / 2
                origin.y: flipable.height / 2
                axis.x: 0; axis.y: 1; axis.z: 0
                angle: 0
            }

            states: State {
                name: "back"
                when: flipable.flipped
                PropertyChanges { target: rotation; angle: 180 }
            }

            transitions: Transition {
                NumberAnimation {
                    target: rotation
                    property: "angle"
                    duration: 600
                    easing.type: Easing.InOutQuad
                }
            }

            MouseArea {
                anchors.fill: parent
                cursorShape: Qt.PointingHandCursor
                onClicked: flipable.flipped = !flipable.flipped
            }
        }

        Text {
            text: "当前: " + (flipable.flipped ? "背面" : "正面")
            font.pointSize: 10
            color: "#666"
        }
    }
}

Flipable 做翻转,思路分四步:正反两面(front 和 back)先定义好,再使用 Rotation 用于旋转,用 states 声明翻到背面这个状态,最后由 transitions 把状态切换变成动画。

转动方向由 Rotation 的轴来决定,将轴设成竖轴就是扑克牌式的左右翻,改成横轴就变成上下翻。

还有个容易踩的小坑:旋转原点要放在组件中心,否则会绕着角落转,翻出来的效果是歪的。整套翻转说白了就是 状态变化 + 动画过渡。

适用场景:扑克牌、抽卡、正反面信息卡片。

Flipable 登录设置

登录界面和设置界面共用同一个 Flipable:

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "components"

FadeInAnimation {

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        Flipable {
            id: flipable
            Layout.fillWidth: true
            Layout.fillHeight: true

            property bool flipped: false

            front: Rectangle {
                anchors.fill: parent
                color: "#f8f9fa"
                radius: 6

                ColumnLayout {
                    anchors.fill: parent
                    anchors.margins: 16
                    spacing: 12

                    Text {
                        text: "用户登录"
                        font.pixelSize: 16
                        font.bold: true
                        color: "#333"
                        Layout.alignment: Qt.AlignHCenter
                    }

                    IconTextField {
                        id: usernameField
                        Layout.fillWidth: true
                        placeholderText: "请输入用户名"
                        iconSource: "qrc:/images/user-icon.png"
                    }

                    IconTextField {
                        id: passwordField
                        Layout.fillWidth: true
                        placeholderText: "请输入密码"
                        echoMode: TextField.Password
                        iconSource: "qrc:/images/lock-icon.png"
                    }

                    RowLayout {
                        Layout.fillWidth: true
                        Item { Layout.fillWidth: true }
                        Button {
                            text: "登录设置"
                            flat: true
                            font.pixelSize: 12
                            onClicked: flipable.flipped = true
                        }
                    }

                    PrimaryButton {
                        text: "登 录"
                        Layout.fillWidth: true
                        enabled: usernameField.text !== "" && passwordField.text !== ""
                        onClicked: console.log("登录:", usernameField.text)
                    }
                }
            }

            back: Rectangle {
                anchors.fill: parent
                color: "#f8f9fa"
                radius: 6

                ColumnLayout {
                    anchors.fill: parent
                    anchors.margins: 16
                    spacing: 12

                    Text {
                        text: "登录设置"
                        font.pixelSize: 16
                        font.bold: true
                        color: "#333"
                        Layout.alignment: Qt.AlignHCenter
                    }

                    CheckBox {
                        text: "记住密码"
                        Layout.fillWidth: true
                    }

                    CheckBox {
                        text: "自动登录"
                        Layout.fillWidth: true
                    }

                    CheckBox {
                        text: "启用指纹登录"
                        Layout.fillWidth: true
                    }

                    Item { Layout.fillHeight: true }

                    PrimaryButton {
                        text: "保存并返回"
                        Layout.fillWidth: true
                        onClicked: flipable.flipped = false
                    }
                }
            }

            transform: Rotation {
                id: rotation
                origin.x: flipable.width / 2
                origin.y: flipable.height / 2
                axis.x: 0; axis.y: 1; axis.z: 0
                angle: 0
            }

            states: State {
                name: "back"
                when: flipable.flipped
                PropertyChanges { target: rotation; angle: 180 }
            }

            transitions: Transition {
                NumberAnimation {
                    target: rotation
                    property: "angle"
                    duration: 600
                    easing.type: Easing.InOutQuad
                }
            }
        }
    }
}

这个 demo 把翻转效果应用到了实际的场景中,front 是登录表单,用户名、密码、登录按钮齐全;back 是设置页。

点击按钮(登录设置),代码将 flipped 设置为 true 并翻到设置页,点击按钮(保存并返回)置回 false 翻回来,翻转动画和刚才的demo一样。

适用场景:登录/设置切换、引导页翻页、同区域双界面的轻量切换。


已验证环境:

相关推荐
阿钱真强道8 小时前
24 嵌入式操作系统 | 项目启动与环境准备(PyQt5 / Flask 两个“最小可跑“)
开发语言·qt·flask·架构设计·协议契约
物极必反102411 小时前
QT使用FFMpeg编译安卓程序.md
qt·ffmpeg·安卓
励志不掉头发的内向程序员16 小时前
【从零写一个CAD 03】三个 double 值得单独一个类吗:把视图变换抽成 View
开发语言·c++·qt·学习·系统架构
sycmancia1 天前
Qml——第一个qml的程序
qt
实心儿儿1 天前
Qt — Qt 多线程
开发语言·qt
沫璃染墨1 天前
《Qt从零入门系列(十一):Qt事件机制详解——从QEvent到鼠标、键盘与定时器事件》
c++·qt·ui·硬件工程·交互·个人开发·qt5
实心儿儿1 天前
Qt — Qt 窗口
开发语言·qt
Quz1 天前
QML 滚动条:自定义滚动样式与滚动逻辑
qt
Quz1 天前
QML 滚动视图:ScrollView、Flickable,以及 ScrollIndicator 用法
qt