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一样。

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


已验证环境:

相关推荐
zhanghaha131410 小时前
Qt 类本质就是 C++ 的类,只是 Qt 框架扩展了一套【QObject 对象模型】
qt
Cx330❀18 小时前
深入浅出 Qt 绘图机制:从 QPainter 到四大图像类解析
开发语言·qt·ui·性能优化·图形渲染
Littlehero_12119 小时前
QT自定义控件之水泥厂组态(源码开源)
开发语言·qt
代钦塔拉1 天前
【C++/Qt 进阶】设计模式系列(6):桥接模式——把“两个独立变化的维度“拆开
c++·qt·设计模式
156082072191 天前
银河麒麟 Qt 可执行文件打包说明
开发语言·驱动开发·qt
Quz1 天前
QML GridView 布局:网格排布与排列方向
qt
Quz1 天前
QML GridView 动态:增删过渡与滚动定位
qt
沫璃染墨2 天前
《Qt从零入门系列(十四):QThread多线程详解——从线程创建到客户端阻塞处理》
开发语言·c++·笔记·qt·ui·交互·线程
代钦塔拉2 天前
【C++/Qt 进阶】设计模式系列(5):适配器模式——给“不兼容的接口“贴一层翻译膜
c++·qt·设计模式
把我格子衫拿来2 天前
VTK 9.5 与 Qt 6 联合开发:从嵌入三维窗口到可维护的桌面架构
c++·python·qt·vtk·三维可视化