动画效果

来源地址: https://uimovement.com/media/resource_image/image_5213.gif.mp4

下图是我仿制的动画:

实现思路

动画的实现

  1. 锁图标由白色变成了黑色. 锁的图标我们可以通过 Image 对象加载. 白色变黑色则通过附加在 Image 上的 ColorOverlay 实现.
  2. 密码由星号变成明文. 为了让变化自然, 我们对星号渐隐, 明文渐入转换.
  3. 白色矩形覆盖填充到整个按钮. 用 QML 来实现是比较简单的, 就是一个属性动画. 我们对白色矩形 (初始时的圆形) 的各个子属性添加属性动画, 指定它末状态的值就能做出来.
  4. 眨眼动画. 这个仔细看不是简单的两张静态图的切换, 我没有找到合适的素材, 所以就用 gif 录制工具把原版的眨眼截取下来了 (如下图所示), 再把 gif 套到一个白色圆形中, 遮掩一下它方正的边缘.

QML 布局结构

对 QML 的组织采用面向对象的思想. 把每一个组件看作是对象, 组件之间嵌套组合构成了完整的 UI.

WindowPasswordLockIconPwdTextEyesBlink

代码及注释

说明

  • 详细的说明以通过注释的形式给出.
  • 代码中的属性和变量命名风格做了自定义, 相关阅读见此 (TODO).
  • 深入了解 QML 对象的使用, 请查阅 Qt 助手工具.

目录结构

demo
|- ui|- Main.qml  # 这里是 ui 的主入口.|- Password|- Main.qml  # 这里是 Password 组件的主入口, 将被加载到 ui/Main.qml 中.|            # 下面的 LockIcon.qml, PwdText.qml, EyesBlink.qml 则会被本|            # 文件引用.|- LockIcon.qml|- PwdText.qml|- EyesBlink.qml
|- icon|- lock-white.png|- eyes-blink.gif
|- main.py

代码

// === ui/Main.qml ===
import QtQuick.Window 2.14
import "./Password" as PasswordWindow {color: "#EDEDED"visible: truewidth: 1200; height: 600Password.Main {id: _pwdanchors.centerIn: parent}
}
// === ui/Password/Main.qml ===
import Qt3D.Animation 2.14  // 动画模块
import QtQuick 2.14Rectangle {  // ui/Password/Main.qml 是密码框的主体. 在其内引用其他子组件文件.id: _root// 设置一个深蓝色的长条状的矩形作为密码框的主体.color: "#172336"radius: 24width: 480; height: 80// 声明两个自定义的变量.property bool p_active: false  // 是否处于激活状态. 默认为 false. 只有当密码框被点击时才会变成 true.property int p_duration: 5000  // 动画的时长. 5000ms 的慢动作是为了便于调试时观察; 正式结果将改为 500ms.// 定义激活时的状态. 在这里我们只定义了白色遮罩的激活状态 (也就是末状态). 其他组件 (锁, 密码文字, 眼睛) 则在各自的 qml 文件中定义, 不在这里写.states: [State {when: p_active  // 监听 p_active 变量, 当值为 true 时此状态被激发.PropertyChanges {  // 定义末状态的属性和值.target: _rect_mask  // 目标对象是白色遮罩的 id.anchors.margins: 0  // 边距调为 0.width: _root.width; height: _root.height; radius: _root.radius  // 宽, 高, 弧度变为根对象的值.x: _root.x; y: _root.y  // 坐标 (左上角顶点的坐标) 也变为根对象的值.}}]// 当 states 列表的任意一个状态被激发时, transitions 就会因此产生动画效果.transitions: [Transition {// 我们定义一个数字类型的属性动画. 因为宽, 高, 弧度等值都是数字类型的.NumberAnimation {  target: _rect_maskduration: p_duration  // 动画时长. 就是我们刚才定义的 5000ms.easing.type: Easing.OutQuart  // 为了让动画看起来自然, 我们使用非线性插值器. Easing.OutQuart 的效果是开始时快, 结束时非常缓慢, 适合表现飞入视界并获取焦点的效果.properties: "anchors.margins,height,radius,width,x,y"  // 指定白色遮罩对象的这些属性发生变化.}}]// 白色遮罩. 始状态是一个圆形, 位于密码框的右侧.Rectangle {id: _rect_mask// 对齐: 对齐到根对象右侧, 边距为 24px, 与根对象垂直居中.anchors.margins: 24anchors.right: _root.rightanchors.verticalCenter: _root.verticalCentercolor: "white"width: 48; height: 48; radius: 24  // 注意看这里, 当 width == height 且 radius == 1/2 width 时, 矩形就是一个圆形.// 绑定点击区域.MouseArea {anchors.fill: _rect_maskonClicked: {p_active = true  // 当白色遮罩被点击时, p_active 变为 true. 这时候我们再去看 states. State 的 when 属性会自动监听到这个变化, 并激发这个状态, 从而引起 transitions 动画生效, 整个动画开始发生.}}}// 右侧的眨眼动画. 因为这个 gif 是方形的, 所以和白色遮罩叠在一起, 把方形边缘遮住.EyesBlink {id: _eye// 这个对齐值是反复调整出来的. 最终要的效果是: 看起来要比白色遮罩小, 不能把方形边缘漏出来, 还要看起来位于其中心.anchors.right: _root.rightanchors.rightMargin: 34anchors.top: _lock.topanchors.topMargin: 4width: 28; height: 28// 把根对象的 p_active 绑定到动画播放属性上. 这样点击时才会播放眨眼动作.p_active: _root.p_activespeed: 4  // 注意 EyesBlink 的动画时长不遵循 p_duration, 而是其 gif 文件的时长除以 speed. speed 默认为 1, 这里被我设置成了 4, 为了看起来更快一点.}// 锁图标的组件. 这里只覆写了锚点, 尺寸和变量属性. 详见 ui/Password/LockIcon.qml.LockIcon {id: _lockanchors.left: _root.leftanchors.margins: 24anchors.verticalCenter: _root.verticalCenterp_active: _root.p_activep_duration: _root.p_durationobj_Image {width: 32; height: 32}}// 密码文字的组件. 这里只覆写了锚点和变量属性. 详见 ui/Password/PwdText.qml.PwdText {anchors.left: _lock.rightanchors.leftMargin: 12anchors.verticalCenter: _root.verticalCenterp_active: _root.p_activep_duration: _root.p_duration}
}
// === ui/Password/LockIcon.qml ===
import QtGraphicalEffects 1.14  // 用于制作 ColorOverlay
import QtQuick 2.14Item {width: _icon.width; height: _icon.heightproperty alias obj_Image: _icon  // 将子对象图标暴露给外部. 从而使父级可以引用 (因为我们想在父级定义它的宽度和高度).property bool p_active: false  // 激活状态. 默认为 false. 同样被父级定义, 此属性会被绑定到父级的 p_active 属性上.property int p_duration: 0  // 动画时长. 同样被父级定义.// 透明背景的锁形图标.Image {id: _iconsource: "../../icon/lock-white.png"}// 由于锁图标是白色的, 我们需要在 p_active = true 状态将它变成黑色, 所以使用 ColorOverlay 实现.// ColorOverlay 可以覆盖目标对象的颜色, 并且我们还可以对 ColorOverlay 的 color 属性绑定一个过渡动画.ColorOverlay {id: _overlaysource: _iconanchors.fill: _icon//color: "white"}// 定义默认状态和激活状态的 ColorOverlay.states: [State {name: "defaultState"when: !p_activePropertyChanges {target: _overlaycolor: "white"}},State {name: "activeState"when: p_activePropertyChanges {target: _overlaycolor: "black"}}]// 当状态发生变化时, Transition 会被自动触发, 实现动画过程.transitions: [Transition {ColorAnimation {target: _overlayduration: p_duration}}]
}
// === ui/Password/PwdText.qml ===
import QtQuick 2.14Text {/* 密码文字存在两种状态:*     默认状态: 密文显示. 以星号 (*) 显示, 密文的长度是 12 个星号.*     激活状态: 明文显示, 这里用 "<this is the real password>" 简单代替.* 动画:*     密码文字由不透明转为透明, 再由透明转为不透明. 当完全透明的那一刻, 迅*     速将密码文字由密文切换为明文.*     简单来说就是密文隐去, 随之明文渐现.*/id: _rootcolor: "#585DC5"font.pixelSize: 24opacity: 1  // 不透明度. 数值从 0.0 到 1.0. (1.0 为完全显示.)text: "* ".repeat(p_pwdLength)  // 为了让星号之间空隙大一点, 我夹了空格.property bool p_active: false  // 激活状态. 默认为 false. 同样被父级定义, 此属性会被绑定到父级的 p_active 属性上.property int p_duration: 0  // 动画时长. 同样被父级定义.property int p_pwdLength: 12// 我们监听 opacity 属性的变化, 当 opacity 变化时, 此信号会被自动触发.onOpacityChanged: {// 进入一个判断逻辑: 当完全透明且处于 p_active 状态, 则将 text 变成明文.if (opacity == 0 && p_active) {text = "<this is the real password>"}}states: [State {name: "showPwdInPlainText"when: p_activePropertyChanges {target: _rootopacity: 1}}]transitions: [Transition {  // 使用序列动画. 前 20% 时间是渐隐动画, 后 80% 时间是渐入动画.SequentialAnimation {NumberAnimation {duration: p_duration * 0.2easing.type: Easing.OutQuartproperties: "opacity"from: 1; to: 0}  // 注意这里不要有逗号.NumberAnimation {duration: p_duration * 0.8easing.type: Easing.OutQuartproperties: "opacity"from: 0; to: 1}}}]
}
// === ui/Password/EyesBlink.qml ===
import QtQuick 2.14AnimatedImage {  // AnimatedImage 对象专用于加载可动的图像. 详见 Qt 助手 QML > AnimatedImage.id: _imgplaying: p_active  // 初始化载入时, gif 动画设为暂停状态.source: "../../icon/eyes-blink.gif"property bool p_active: false  // 激活状态. 默认为 false. 同样被父级定义, 此属性会被绑定到父级的 p_active 属性上.// 当 AnimatedImage 播放时, 其 currentFrame 会发生变化, 此信号的内置监听方法 onCurrentFrameChanged 会被自动触发.// 我们判断当 currentFrame 播放到最后一帧时, 停止动画, 以免陷入循环播放.onCurrentFrameChanged: {if (currentFrame == frameCount - 1) {  // 因为 currentFrame 是从 0 开始数的, 所以这里要减一.playing = false// paused = true}}
}

最后是 main.py 代码:

# === main.py ===
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QApplicationapp = QApplication()
engine = QQmlApplicationEngine('./ui/Main.qml')
app.exec_()

源码及附件

源码及图标文件以打包, 下载链接见此: https://lanzous.com/ica5cla

PyQt (PySide) 使用 QML 仿制一个密码框动画相关推荐

  1. 解决 input密码框自动填充

    火狐上input密码框自动填充值的有关问题 By wangzhehui   at 2014-06-07   117 阅读   0 回复   0.0 希赛币 请点击下面回答中的"采纳为答案&q ...

  2. html语言密码框,HTML表单密码框INPUT标签

    HTML表单密码框标签 在HTML的表单控件中,密码框也是经常使用的控件,它主要用户密码验证.密码修改等地方,它使用的也是标签. 一.定义 标签用于表示文本框.密码框.单选框.复选框.文件上传框.普通 ...

  3. angularjs html 支付宝支付,angular仿支付宝密码框输入效果

    项目需求,使用ng写一个密码框格子支付模块,一开始使用一个input+letter-spacing来分割字符,但是发现间距非常不好控制,随着字符的输入文本框字符串间距还会自动调整.最终从网上查找到一款 ...

  4. WPF教程(二十)密码框

    WPF中编辑常规的文字都是使用文本框,但是如果是输入密码呢?功能应该是一样的,但是我们不想周边的人看着我们一个字母一个字母的输入,这样密码就被泄漏了,因此我们想用别的字符来替代真实密码的显示.出于这个 ...

  5. Dell笔记本、Win10系统开机时没有密码框的一个解决办法。

    Dell笔记本.Win10系统开机时没有密码框的一个解决办法. 我是因为之前安装tensorflow-gpu,操作不当,导致的这个问题,之后也看了很多博主提供的好的方法,很多小伙伴们也通过这些方法问题 ...

  6. 16、HTML密码框

    网页中最典型的应用密码框的场景就是网站的登录注册页面 在 HTML 中,把 <input> 标签的 type 属性设置为 password 可以表示密码框.具体语法格式如下: <in ...

  7. Java窗口(JFrame)从零开始(8)——文本框+文本域+密码框

    应该最后一章了,前面有大神提到很少有人用Java做UI,这里就算是给像我这样的初学者去了解窗体是怎么一回事的文章吧 文本框(JTextField) 构造方法摘要 JTextField() 构造一个新的 ...

  8. Chrome浏览器密码框自动填充的bug

    在系统开发过程中,有一个难啃的bug从入职以来都在debug,一直以为是下拉框控件导致的问题.所以这个问题一直就搁浅了.今儿bug重提,就一步步找原因,排除了下拉控件select2的原因,才发现是在C ...

  9. html密码框不显示,密码框中密码的显示与隐藏切换(JS)

    目标: 点击小眼睛后, 1.密码框变成文本框: 2.小眼睛图片由闭眼变成睁眼: 3.再次点击后,又变成闭眼+密码框 要想实现3,方法1: 则需要一个变量,来辅助判断当前input的属性,如果flag为 ...

最新文章

  1. 你知道Spring Boot项目是怎么启动的吗?
  2. mysql5.6.37驱动_mysql 5.6.37(zip)下载安装配置图文教程
  3. 重温ES6核心概念和基本用法
  4. 32岁的老程序员面试没通过,一问原因,挺突然的...
  5. VTK:几何对象之QuadraticHexahedron
  6. hadoop学习笔记(三):hdfs体系结构和读写流程(转)
  7. Spring+SpringMvc+Mybatis框架集成搭建教程二(依赖配置及框架整合)
  8. Luogu P2577 [ZJOI2005]午餐
  9. 【渝粤题库】国家开放大学2021春1283社会保障学(本)题目
  10. php 获取一年的月份_php 根据日期获取星座
  11. 069 模块基础总结
  12. 廖雪峰Java9正则表达式-2正则表达式进阶-3分组匹配
  13. Java类的三大特性
  14. 【谷月老师讲WPS】用 Windows 11 的 WSL 安装 WPS for Linux
  15. Python IndentationError: expected an indented block
  16. 清除Windows虚机密码
  17. ui-bootstrap-tpls 中文 现在还不全的啊~,组件太多了,有空就更新
  18. Windows日志分析(中)
  19. java设计校园网登录界面_java毕业设计_springboot框架的校园网的大学生社交网站...
  20. 搭建easy-mock数据模拟服务器

热门文章

  1. showModalDialog的兼容性处理方案
  2. Bartender 4 for Mac菜单栏无忧管理
  3. 这篇文章讲了一个新科技
  4. 推荐十个精彩的Ubuntu鼠标主题
  5. 视频教程-Word2016经典视频教程-初级版-Office/WPS
  6. MySql 获取表的字段名
  7. poj3208 Apocalypse Someday 题解报告
  8. make menuconfig缺少ncurses
  9. Android手游SDK那点事(四)聚合打包
  10. kdb内核调试 - 5