带你一起Piu Piu Piu

自定义WPF动画实现小球动态发射与轨迹变化
本文介绍了如何在WPF中自定义动画,通过修改原始例子来实现小球的动态发射、轨迹变化及帧率调整。包括背景、文字修改,动画逻辑优化,以及小球抛物线弧度的可调节性。此外,通过添加间隔滑块、模式切换等功能,实现了小球发射角度、大小和颜色的随机变化。最后,展示了最终效果并提供了代码下载。
单刀直入,今天要讲的是自己写的一个WPF动画例子。我们在看下最终效果~

最终效果图
最近在重看WPF编程宝典2010,在练习第15章动画性能例子时有了些想法。原始例子如下:
原始例子
原始例子(打包了整个15章的)
它是一个可动态改变小球动画帧速的程序~那我能不能让小球一直发射?能不能改变小球的轨迹?
所有就有了现在的程序,我们先改变背景和文字(请原谅消音枪的Piu不知道是那个字)这里写图片描述
这里写图片描述
首先把原来的文本框输入改为Slider,不然输入个文字在点程序就JJ了~然后我们把前台的动画放到后台来实现,每次都创建一个小球。开始动画,结束后在删除~代码如下:

  <Grid>
        <Grid Margin="5">
            <Border BorderBrush="#FFA44545" BorderThickness="2">
                <Canvas Name="Cvs" ClipToBounds="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="#FFB5D7DE">
                    <Canvas.Resources>
                        <Style TargetType="Ellipse">
                            <Setter Property="Fill" Value="Red"></Setter>
                            <Setter Property="Width" Value="10"></Setter>
                            <Setter Property="Height" Value="10"></Setter>
                        </Style>
                    </Canvas.Resources>
                </Canvas>
            </Border>
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,40" Orientation="Horizontal">
                <TextBlock Margin="5,0">动画帧率:</TextBlock>
                <Slider x:Name="Sdr_FrameRate" Width="100" Maximum="100" Minimum="10" Value="60" ToolTip="{Binding Value, ElementName=Sdr_FrameRate}" IsSnapToTickEnabled="True" IsMoveToPointEnabled="True"/>
            </StackPanel>
            <Button Name="btnRepeat"  HorizontalAlignment="Center" VerticalAlignment="Bottom" Content="Piu piu Piu" Padding="5" Click="btnRepeat_Click" Margin="0,0,0,10"></Button>
        </Grid>
    </Grid>
  private void btnRepeat_Click(object sender, RoutedEventArgs e)
        {
            //创建一个圆形的小球
            Ellipse elp = new Ellipse();
            Cvs.Children.Add(elp);

            DoubleAnimation leftAnimation = new DoubleAnimation(0, 600, TimeSpan.FromSeconds(5));

            leftAnimation.Completed += leftAnimation_Completed;
            //设置动画的帧速
            Timeline.SetDesiredFrameRate(leftAnimation, (int)Sdr_FrameRate.Value);
            //开始宽度位移动画
            elp.BeginAnimation(Canvas.LeftProperty, leftAnimation);

            DoubleAnimation topAnimation = new DoubleAnimation(400, 0, TimeSpan.FromSeconds(2.5))
            {
                DecelerationRatio = 1,
                AutoReverse = true
            };
            Timeline.SetDesiredFrameRate(topAnimation, (int)Sdr_FrameRate.Value);
            //开始高度位移动画
            elp.BeginAnimation(Canvas.TopProperty, topAnimation);
        }

        /// <summary>
        /// 运行完动画后从画布删除小球
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void leftAnimation_Completed(object sender, EventArgs e)
        {
            if (Cvs.Children.Count > 0)
                Cvs.Children.RemoveAt(0);
        }

在这里我发现一个问题,当前角度实际是因为高度时间为宽度的一半,所以有曲线的动画。并且动画用的固定的窗体高宽,那么当窗体大小发生变化时就会很奇怪(注意下张图小球消失的地方)~
这里写图片描述
所以我们把600,400换成窗体的ActualWidth和ActualHeight(不要使用width和height,因为它们不会随窗体一起改变大小)。这里写图片描述
那我们能不能尝试改变的抛物线的弧度呢?(也就是Height动画的时间)假设想使用三种弧度方式固定、递增和随机来动画小球~并且可控制递增的间隔。先来改前台:

          <StackPanel x:Name="stackPanel" HorizontalAlignment="Center" VerticalAlignment="Bottom" Orientation="Horizontal" Margin="0,0,0,66">
                <TextBlock TextWrapping="Wrap" Text="间隔:"/>
                <Slider x:Name="Sdr_Interval" Minimum="0.1" Maximum="1" TickFrequency="0.1" Width="100" Margin="5,0,0,0" ToolTip="{Binding Value, ElementName=Sdr_Interval}" IsSnapToTickEnabled="True" IsMoveToPointEnabled="True"/>
            </StackPanel>
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,40" Orientation="Horizontal">
                <TextBlock>动画角度:</TextBlock>
                <RadioButton Margin="5,0" Checked="RadioButton_Checked" Tag="1">固定</RadioButton>
                <RadioButton x:Name="radioButton" Margin="5,0"  Checked="RadioButton_Checked" Unchecked="RadioButton_Unchecked" Tag="2" IsChecked="True">递增</RadioButton>
                <RadioButton Margin="5,0"  Checked="RadioButton_Checked" Tag="3">随机</RadioButton>
                <TextBlock Margin="5,0">动画帧率:</TextBlock>
                <Slider x:Name="Sdr_FrameRate" Width="100" Maximum="100" Minimum="10" Value="60" ToolTip="{Binding Value, ElementName=Sdr_FrameRate}" IsSnapToTickEnabled="True" IsMoveToPointEnabled="True"/>
            </StackPanel>

第一个好解决我们就使用2.5秒,第二个我们使用1秒每次小球+0.1秒,这样弧度就会增加。效果如下:
这里写图片描述

现在我们发现了些问题,一个是间隔的Slider只和递增有关,切到别的模式应该不显示。所有我们使用Blend加个切换动画。然后小球是在文字的后方的,应该设置下Zindex。最后当切会递增时,它的初始角度应该恢复。OK,我们修改如下~这里写图片描述
这里写图片描述
这个发现了一个奇怪的问题就是设置间隔Slider的刻度,0.1、0.2都没有问题但0.3就变成了
这里写图片描述
还有小球是在控件之下文字之上~另外就是我想给Slider指向显示加上前缀文字,如:当前间隔为:0.2。惭愧以上几个问题没解决这里写图片描述如果有人知道,还麻烦告诉我下~
好了,进入最后一项。随机!我打算让小球的大小、时间和颜色全部都随机。代码如下:

            //递增初始时间
            double duraTime = 1;
            //判断模式
            switch (AnageMode)
            {
                case 1:
                    duraTime = 2.5;
                    break;
                case 2:
                    duraTime = timeSpan += Sdr_Interval.Value;
                    break;
                case 3:
                    random = new Random((int)DateTime.Now.Ticks);
                    duraTime = random.Next(1, 10);
                    elp.Height = elp.Width = random.Next(3, 20);
                    elp.Fill = new SolidColorBrush(new Color()
                    {
                        A = 255,
                        R = (byte)random.Next(0, 255),
                        G = (byte)random.Next(0, 255),
                        B = (byte)random.Next(0, 255)
                    });
                    break;
            }

            DoubleAnimation topAnimation = new DoubleAnimation(this.ActualHeight, 0, TimeSpan.FromSeconds(duraTime))
            {
                DecelerationRatio = 1,
                AutoReverse = true
            };

真正最终效果如下:
这里写图片描述
其实,你本地全屏看的固定的有尾巴像流星有没有?而降低帧速率时,动画会很卡!你可能发现了随机的时候只有一个方向,而最开始是两个方向的~对,只要我们同时加两个小球,并把动画反过来就好了!最后附上下载,明天就要回家了。第一次写求指点~这里写图片描述

### 关于前端 PIU 技术文档和常见问题解决方案 #### 前端 PIU 的定义和技术背景 PIU (Progressive Image Upload),即渐进式图片上传技术,是一种优化用户体验的技术方案。这种技术允许用户在网页上快速预览低分辨率版本的图像,在后台继续处理高分辨率版本并最终替换之。这种方式不仅提高了用户的交互体验,还有效减少了服务器宽压力。 #### 技术实现要点 为了实现高效的 PIU 功能,通常会采用如下策略: - **多阶段压缩**:先生成缩略图供即时显示,随后异步加载原始尺寸图片[^1]。 - **懒加载机制**:仅当视窗滚动至接近目标区域时才触发实际资源请求,减少不必要的网络流量消耗[^2]。 - **缓存管理**:合理设置 HTTP 缓存头信息,确保浏览器能够正确存储已下载过的文件副本,加快重复访问速度[^3]。 ```javascript // JavaScript 实现懒加载的一个简单例子 document.addEventListener('DOMContentLoaded', function() { const lazyImages = [].slice.call(document.querySelectorAll('img.lazy')); if ('IntersectionObserver' in window) { let lazyImageObserver = new IntersectionObserver(function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { let lazyImage = entry.target; lazyImage.src = lazyImage.dataset.src; lazyImage.classList.remove('lazy'); lazyImageObserver.unobserve(lazyImage); } }); }); lazyImages.forEach(function(lazyImage) { lazyImageObserver.observe(lazyImage); }); } else { // Fallback for browsers not supporting Intersection Observer API. let oldSrc, img; lazyImages.forEach(function(image) { oldSrc = image.getAttribute('data-src'); img = document.createElement('img'); img.onload = function() {image.parentElement.replaceChild(img, image);}; img.src = oldSrc; }); } }); ``` #### 解决常见问题的方法论 针对可能出现的问题,建议采取以下措施来保障系统的稳定性和性能: - 对于大文件传输过程中断的情况,考虑引入分片重传逻辑或者利用 HTML5 File API 结合 WebSocket 进行实时同步[^4]; - 如果遇到跨域资源共享(CORS)错误,则需确认前后端配置是否一致,并适当调整 Access-Control-Allow-Origin 头部字段值; - 当页面响应时间过长影响到用户体验时,可以通过 CDN 加速静态资源分发、启用 Gzip/Br 压缩等方式改善整体效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值