SOUI 动画集合 (AnimatorSet)¶
概述¶
SOUI 动画集合(SAnimatorSet)提供了一种机制来组合和控制多个 SValueAnimator 对象的播放顺序和方式。它可以将多个动画按顺序或并行播放,使得复杂的动画序列变得易于管理。
SAnimatorSet 本身也是一个动画器(继承自 IValueAnimator),这意味着它可以像其他动画器一样使用,甚至可以嵌套到其他动画集合中。
核心概念¶
动画依赖关系¶
SAnimatorSet 通过建立动画之间的依赖关系来控制它们的播放顺序:
- 并行(Parallel):多个动画同时播放
- 串行(Sequential):动画按顺序一个接一个播放
AnimatorSetPlayMode¶
- PARALLEL:并行模式,所有动画同时开始
- SEQUENCE:串行模式,动画按顺序播放
主要方法¶
| 方法 | 描述 |
|---|---|
| addAnimator(IValueAnimator * pAnimator) | 添加动画到集合(默认并行播放) |
| addAnimatorAfter(IValueAnimator * pAnimator, IValueAnimator * pAfterAnimator) | 添加在指定动画之后播放的动画 |
| addAnimatorWith(IValueAnimator * pAnimator, IValueAnimator * pWithAnimator) | 添加与指定动画并行播放的动画 |
| removeAnimator(IValueAnimator * pAnimator) | 从集合中移除动画 |
| removeAllAnimators() | 移除所有动画 |
| getAnimatorCount() | 获取动画数量 |
| getAnimatorAt(int index) | 获取指定索引的动画 |
| setPlayMode(AnimatorSetPlayMode mode) | 设置播放模式(并行或串行) |
| getPlayMode() | 获取当前播放模式 |
使用示例¶
并行动画¶
void CMainDlg::OnParallelAnimation()
{
SWindow * pWnd_left_top = FindChildByName(L"set_left_top");
SWindow * pWnd_right_top = FindChildByName(L"set_right_top");
SWindow * pWnd_left_bottom = FindChildByName(L"set_left_bottom");
SWindow * pWnd_right_bottom = FindChildByName(L"set_right_bottom");
if (!pWnd_left_top || !pWnd_right_top || !pWnd_left_bottom || !pWnd_right_bottom)
return;
// 创建动画集
SAutoRefPtr<SAnimatorSet> animatorSet = new SAnimatorSet();
animatorSet->setPlayMode(PARALLEL); // 设置为并行模式
// 获取各窗口的当前位置
AnchorPos anchorPos[4];
_GetWindowAnchorPos(pWnd_left_top, anchorPos + 0);
_GetWindowAnchorPos(pWnd_right_top, anchorPos + 1);
_GetWindowAnchorPos(pWnd_left_bottom, anchorPos + 2);
_GetWindowAnchorPos(pWnd_right_bottom, anchorPos + 3);
// 动画1:左上角窗口向右下移动
{
AnchorPos pos[] = {
anchorPos[0],
anchorPos[3]
};
IPropertyAnimator *pAnimator = SPropertyAnimator::ofPosition(
pWnd_left_top,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator)
{
animatorSet->addAnimator(pAnimator);
pAnimator->Release();
}
}
// 动画2:右上角窗口向左下移动
{
AnchorPos pos[] = {
anchorPos[1],
anchorPos[2]
};
IPropertyAnimator *pAnimator = SPropertyAnimator::ofPosition(
pWnd_right_top,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator)
{
animatorSet->addAnimator(pAnimator);
pAnimator->Release();
}
}
// 启动动画集
if (animatorSet)
{
animatorSet->start(this);
}
}
串行动画¶
void CMainDlg::OnSequentialAnimation()
{
SWindow * pWnd_left_top = FindChildByName(L"set_left_top");
SWindow * pWnd_right_top = FindChildByName(L"set_right_top");
SWindow * pWnd_left_bottom = FindChildByName(L"set_left_bottom");
SWindow * pWnd_right_bottom = FindChildByName(L"set_right_bottom");
if (!pWnd_left_top || !pWnd_right_top || !pWnd_left_bottom || !pWnd_right_bottom)
return;
// 创建动画集
SAutoRefPtr<SAnimatorSet> animatorSet = new SAnimatorSet();
animatorSet->setPlayMode(SEQUENCE); // 设置为串行模式
// 获取各窗口的当前位置
AnchorPos anchorPos[4];
_GetWindowAnchorPos(pWnd_left_top, anchorPos + 0);
_GetWindowAnchorPos(pWnd_right_top, anchorPos + 1);
_GetWindowAnchorPos(pWnd_left_bottom, anchorPos + 2);
_GetWindowAnchorPos(pWnd_right_bottom, anchorPos + 3);
// 创建四个动画,按顺序执行
SAutoRefPtr<IPropertyAnimator> pAnimator1 = NULL;
SAutoRefPtr<IPropertyAnimator> pAnimator2 = NULL;
SAutoRefPtr<IPropertyAnimator> pAnimator3 = NULL;
SAutoRefPtr<IPropertyAnimator> pAnimator4 = NULL;
AnchorPos centerPos = {4, 0, 0, -0.5f, -0.5f }; // 中心位置
// 动画1:左上窗口向中心移动
{
AnchorPos pos[] = {
anchorPos[0],
centerPos
};
pAnimator1 = SPropertyAnimator::ofPosition(
pWnd_left_top,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator1)
{
pAnimator1->setDuration(500);
animatorSet->addAnimator(pAnimator1);
}
}
// 动画2:右上窗口向中心移动(在动画1后)
{
AnchorPos pos[] = {
anchorPos[1],
centerPos
};
pAnimator2 = SPropertyAnimator::ofPosition(
pWnd_right_top,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator2)
{
pAnimator2->setDuration(500);
animatorSet->addAnimatorAfter(pAnimator2, pAnimator1);
}
}
// 启动动画集
if (animatorSet)
{
animatorSet->start(this);
}
}
复杂动画集合¶
void CMainDlg::OnComplexAnimatorSetAnimation()
{
SWindow * pWnd_left_top = FindChildByName(L"set_left_top");
SWindow * pWnd_right_top = FindChildByName(L"set_right_top");
SWindow * pWnd_left_bottom = FindChildByName(L"set_left_bottom");
SWindow * pWnd_right_bottom = FindChildByName(L"set_right_bottom");
if (!pWnd_left_top || !pWnd_right_top || !pWnd_left_bottom || !pWnd_right_bottom)
return;
// 创建动画集
SAutoRefPtr<SAnimatorSet> animatorSet = new SAnimatorSet();
// 获取各窗口的当前位置
AnchorPos anchorPos[4];
_GetWindowAnchorPos(pWnd_left_top, anchorPos + 0);
_GetWindowAnchorPos(pWnd_right_top, anchorPos + 1);
_GetWindowAnchorPos(pWnd_left_bottom, anchorPos + 2);
_GetWindowAnchorPos(pWnd_right_bottom, anchorPos + 3);
SAutoRefPtr<IPropertyAnimator> pAnimator1 = NULL;
SAutoRefPtr<IPropertyAnimator> pAnimator2 = NULL;
SAutoRefPtr<IPropertyAnimator> pAnimator3 = NULL;
SAutoRefPtr<IPropertyAnimator> pAnimator4 = NULL;
// ========== 第一阶段 ==========
// 动画1:左上窗口向右移动
{
AnchorPos toPos = {2, 300, anchorPos[0].y, -1, -1 }; // 向右移动
AnchorPos pos[] = {
anchorPos[0],
toPos
};
pAnimator1 = SPropertyAnimator::ofPosition(
pWnd_left_top,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator1)
{
pAnimator1->setDuration(600);
animatorSet->addAnimator(pAnimator1);
}
}
// ========== 第二阶段 ==========
// 动画2:右上窗口向下移动(在动画1后,与动画3并行)
{
AnchorPos toPos = {8, anchorPos[1].x, 300, -1, -1 }; // 向下移动
AnchorPos pos[] = {
anchorPos[1],
toPos
};
pAnimator2 = SPropertyAnimator::ofPosition(
pWnd_right_top,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator2)
{
pAnimator2->setDuration(600);
animatorSet->addAnimatorAfter(pAnimator2, pAnimator1);
}
}
// 动画3:左下窗口向上移动(在动画1后,与动画2并行)
{
AnchorPos toPos = {0, anchorPos[2].x, 100, -1, -1 }; // 向上移动
AnchorPos pos[] = {
anchorPos[2],
toPos
};
pAnimator3 = SPropertyAnimator::ofPosition(
pWnd_left_bottom,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator3)
{
pAnimator3->setDuration(600);
animatorSet->addAnimatorAfter(pAnimator3, pAnimator1);
}
}
// ========== 第三阶段 ==========
// 动画4:右下窗口向左移动(在动画2后)
{
AnchorPos toPos = {6, 100, anchorPos[3].y, -1, -1 }; // 向左移动
AnchorPos pos[] = {
anchorPos[3],
toPos
};
pAnimator4 = SPropertyAnimator::ofPosition(
pWnd_right_bottom,
LayoutProperty::POSITION,
pos,
ARRAYSIZE(pos),
sizeof(AnchorPos)
);
if (pAnimator4)
{
pAnimator4->setDuration(600);
animatorSet->addAnimatorAfter(pAnimator4, pAnimator2);
}
}
// 启动动画集
if (animatorSet)
{
animatorSet->start(this);
}
}
基础动画集合示例¶
// 创建简单的动画集合
SAnimatorSet* animatorSet = new SAnimatorSet();
// 创建透明度动画
float alphaValues[] = {0.0f, 1.0f};
IValueAnimator* alphaAnimator = SPropertyAnimator::ofFloat(
pWindow,
LayoutProperty::ALPHA,
alphaValues,
2
);
alphaAnimator->setDuration(500);
// 创建位置动画
SLayoutSize widthValues[] = {
SLayoutSize(100.0f, dp),
SLayoutSize(200.0f, dp)
};
IValueAnimator* widthAnimator = SPropertyAnimator::ofLayoutSize(
pWindow,
LayoutProperty::WIDTH,
widthValues,
2
);
widthAnimator->setDuration(1000);
// 将动画添加到集合中(并行播放)
animatorSet->addAnimator(alphaAnimator);
animatorSet->addAnimator(widthAnimator);
// 启动动画集合
animatorSet->start(pTimelineHandler);
// 释放资源
alphaAnimator->Release();
widthAnimator->Release();
最佳实践¶
- 合理组织动画顺序:使用 addAnimatorAfter 和 addAnimatorWith 来精确控制动画的播放顺序
- 复用动画对象:对于相同的动画效果,可以复用动画对象以节省资源
- 管理生命周期:确保在适当的时候启动和结束动画集合
- 性能考虑:避免创建过于复杂的动画集合,以免影响性能
- 嵌套使用:可以将动画集合嵌套到其他动画集合中,创建更复杂的动画序列
- 及时释放资源:动画集合结束后及时释放相关资源
总结¶
SAnimatorSet 是 SOUI 动画系统中用于组合和控制多个动画的重要组件。通过它,开发者可以轻松创建复杂的动画序列,包括并行和串行播放的动画组合。它提供了灵活的 API 来定义动画之间的依赖关系,使得复杂的 UI 动画变得易于管理和实现。