[MAUI 项目实战] 手势控制音乐播放器(三): 动画

科技资讯 投稿 5400 0 评论

[MAUI 项目实战] 手势控制音乐播放器(三): 动画

目录
    吸附动画
    • 确定位置
    • 平移动画
  • 回弹动画
      使用自定义缓动函数
  • 多重动画
  • 点击动画
  • 项目地址

  • 上一章节我们创建了手势容器控件PanContainer,它对拖拽物进行包装并响应了平移手势和点击手势。

    本章节我们对拖拽物加入过渡动画

    吸附动画

    接下来对势容器控件PanContainer添加这一效果,打开PanContainer.xaml.cs,创建一个bool类型的可绑定对象AutoAdsorption,用于控制是否开启吸附动画。

    
    public static readonly BindableProperty AutoAdsorptionProperty =
    BindableProperty.Create("AutoAdsorption", typeof(bool, typeof(PanContainer, default(bool;
    
    public bool AutoAdsorption
    {
        get { return (boolGetValue(AutoAdsorptionProperty; }
        set
        {
            SetValue(AutoAdsorptionProperty, value;
            OnPropertyChanged(;
    
        }
    }
    
    

    确定位置

    吸附动画触发时,首先要确定拖拽物的中心点是否在坑区域内,如果在,则拖拽物的中心点移动到坑区域的中心点,否则拖拽物的中心点移动到手指的位置。

    private async void PanGestureRecognizer_OnPanUpdated(object sender, PanUpdatedEventArgs e
    {
        var isInPit = false;
        var isAdsorbInPit = false;
    
    ...
    
        //GestureStatus.Running中
        if (isYin && isXin
        {
            isInPit = true;
            if (AutoAdsorption
            {
                isAdsorbInPit = true;
                translationX = (pitRegion.EndX + pitRegion.StartX - Content.Width / 2;
                translationY = (pitRegion.EndY + pitRegion.StartY - Content.Height / 2;
            }
    
    ...
    
    

    isAdsorbInPit是是否执行吸附动画的标志位。

    平移动画

    使用的用TranslateTo方法执行的,该方法会在200ms内逐渐更改拖拽物的TranslationX和 TranslationY属性

    if (AutoAdsorption
    {
        if (isAdsorbInPit
        {
            if (!IsRuningTranslateToTask
            {
                IsRuningTranslateToTask = true;
                await Content.TranslateTo(translationX, translationY, 200, Easing.CubicOut.ContinueWith(c => IsRuningTranslateToTask = false; ;
            }
    
            isAdsorbInPit = false;
        }
        else
        {
            Content.TranslationX = translationX;
            Content.TranslationY = translationY;
        }
    }
    else
    {
        Content.TranslationX = translationX;
        Content.TranslationY = translationY;
    }
    

    执行效果如下:

    回弹动画

    当手指释放拖拽物时,我们需要对拖拽物进行回弹动画,使其回到原来的位置。

    Easing 类,使用该类可以指定一个传输函数,用于控制动画在运行时如何加快或减慢速度。

    缓动函数 描述
    BounceIn 在开始时弹跳动画
    BounceOut 在结尾处弹跳动画
    CubicIn 缓慢加速动画
    CubicInOut 在开头加速动画,并在结束时减速动画
    CubicOut 会快速减速动画
    Linear 使用恒定的速度,是默认值
    SinIn 可平滑地加速动画
    SinInOut 在开头平滑地加速动画,并在动画结束时平滑减速
    SinOut 平滑地减速动画
    SpringIn 会导致动画快速加速到末尾
    SpringOut 会导致动画快速减速到末尾

    它们的函数曲线如下:

    使用自定义缓动函数

    我用python拟合了一个适合拖拽物回弹的曲线。模拟一种弹性拉扯的效果。

    var mySpringOut =(double x => (x - 1 * (x - 1 * ((5f + 1 * (x - 1 + 5 + 1;
    await Content.TranslateTo(PositionX, PositionY, 200, mySpringOut;
    

    多重动画

    改变大小和改变位置的动画是同时进行的,我们通过创建Animation对象,添加子动画来实现。详情请参考Animation子动画。

     Content.AbortAnimation("ReshapeAnimations";
    var parentAnimation = new Animation(;
    var mySpringOut =(double x => (x - 1 * (x - 1 * ((5f + 1 * (x - 1 + 5 + 1;
    
    var scaleUpAnimation1 = new Animation(v => Content.TranslationX = v, Content.TranslationX, PositionX, mySpringOut;
    var scaleUpAnimation2 = new Animation(v => Content.TranslationY = v, Content.TranslationY, PositionY, mySpringOut;
    var scaleUpAnimation5 = new Animation(v => Content.Scale = v, Content.Scale, 1.0;
    
    parentAnimation.Add(0, 1, scaleUpAnimation1;
    parentAnimation.Add(0, 1, scaleUpAnimation2;
    parentAnimation.Add(0, 1, scaleUpAnimation5;
    
    parentAnimation.Commit(this, "RestoreAnimation", 16, (uintPanScaleAnimationLength;
    
    

    在开始拖拽的时候,也加上缩小的动画,这样拖拽的时候,拖拽物会缩小,释放的时候会恢复原来的大小。

    Content.AbortAnimation("ReshapeAnimations";
    var scaleAnimation = new Animation(;
    var scaleUpAnimation0 = new Animation(v => Content.Scale = v, Content.Scale, PanScale;
    scaleAnimation.Add(0, 1, scaleUpAnimation0;
    
    scaleAnimation.Commit(this, "ReshapeAnimations", 16, (uintPanScaleAnimationLength;
    
    

    注意,放大和缩小是两个成对的动画,他们共同持有一个handler即ReshapeAnimations,不能同时进行,所以在开始一个动画前,要先调用Content.AbortAnimation("ReshapeAnimations"以终止之前的动画。

    点击动画

    在点击时,我们分三次连续的缩小,放大再缩小,这样就会有一个水波纹的效果。

    private void TapGestureRecognizer_OnTapped(object sender, EventArgs e
    {
        var scaleAnimation = new Animation(;
        var scaleUpAnimation0 = new Animation(v => Content.Scale = v, 1.0, 0.9;
        var scaleUpAnimation1 = new Animation(v => Content.Scale = v, 0.9, 1.1;
        var scaleUpAnimation2 = new Animation(v => Content.Scale = v, 1.1, 1.0;
        scaleAnimation.Add(0, 0.3, scaleUpAnimation0;
        scaleAnimation.Add(0.3, 0.6, scaleUpAnimation1;
        scaleAnimation.Add(0.6, 1, scaleUpAnimation2;
    
        scaleAnimation.Commit(this, "ReshapeAnimations", 16, 400;
    
        this.OnTapped?.Invoke(this, EventArgs.Empty;
    }
    

    最终运行效果:

    项目地址

    Github:maui-samples

    编程笔记 » [MAUI 项目实战] 手势控制音乐播放器(三): 动画

    赞同 (30) or 分享 (0)
    游客 发表我的评论   换个身份
    取消评论

    表情
    (0)个小伙伴在吐槽