效果展示:
导语:
相信大家一定用过QQ宠物或360的智能小球吧,你们一定好奇它这神奇的效果是如何完成的?
今天就让我们用 PySide6 / PyQt 复刻它!
首先分析动画:
如上图:这个界面大体是如此构成的。
这个动画分两部分:
- 内容区向上收缩
- 功能菜单向左收缩
- 图片纠正至屏侧
小技巧:
普通动画飞出需要依靠窗口的遮挡或超出显示区域
如何让控件飞出动画不依赖遮挡呢?—— 往控件上在套一层空内容的控件即可
内容缩放:
class ContentWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.mainPage = MainPage(parent=self)
def posAnimation(widget,x,y,s):
move = QPropertyAnimation(widget, b'pos', parent=widget)
move.setDuration(s) # 设置动画时长,单位为毫秒
move.setEndValue(QPoint(x, y))
move.start()
def topScale(self,bl:bool=True):
if bl:
# 向上
posAnimation(self.mainPage, 0, -self.mainPage.height(), self.mainPage.height())
else:
# 向下
posAnimation(self.mainPage, 0, 0, self.mainPage.height())
class mainPage(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
......
上述代码为基本原理,下面我们开始探索动画如何开始和图标位置纠正
动画开始:
观察上图,可以发现窗口到屏幕侧一定距离并且鼠标离开界面收缩动画才会触发
所以重写离开事件和鼠标事件
def mouseMoveEvent(self, event: QMouseEvent) -> None:
super().mouseMoveEvent(event)
if topLeftPos.x() <= 50:
self._inLeft = True
elif bottomRightPos.x() >= self.screenWidth - 50:
self._inRight = True
else:
self._inLeft = False
self._inRight = False
def leaveEvent(self, event):
super().leaveEvent(event)
if self._inLeft:
print('窗口在左侧收缩动画')
elif self._inRight:
sprint('窗口在右侧收缩动画')
elif not self._inLeft and not self._inRight:
print('窗口复原')
图标纠正:
在计算机几何坐标中 原点:屏幕的左上角,最左侧的X坐标都为0,最右侧的X坐标为屏幕宽带最大值
而我们的图标分为以下两种情况:
- 左侧:左上角顶点 (0 , y)
- 右侧:左上角顶点 (screen_x - window_width , y)
纵坐标y 实际为窗口当前纵坐标,不需要做处理
def scaleOutMove(self,bl):
if bl: # 左侧过渡动画
move = QPropertyAnimation(self, b'pos', parent=self)
move.setStartValue(QPoint(
-self.icon.width(),
self.pos().y()
))
move.setEndValue(QPoint(0, self.pos().y()))
move.start()
else: # 右侧过渡动画
move = QPropertyAnimation(self, b'pos', parent=self)
move.setEndValue(QPoint(
self.screenWidth - self.icon.width(),
self.pos().y()
))
move.start()
