C# Avalonia 15- Animation- ImageWipe

news/2025/9/24 13:25:17/文章来源:https://www.cnblogs.com/dalgleish/p/19109062

在上一个AnimationPlayer例子上进行扩展,让其具备完整的小型动画功能。

AnimationPlayer类

    public partial class AnimationPlayer : ObservableObject{// --------------------- 内部类 ---------------------public class TimedAction{public double StartTime { get; set; }public double? EndTime { get; set; }public bool OneTime { get; set; }private bool executed = false;private double fps;internal Action<double>? localAction;internal Action<double>? globalAction;internal Action<double, double>? dualAction;public TimedAction(double startTime, double? endTime = null){StartTime = startTime;EndTime = endTime;}public TimedAction Once(){OneTime = true;return this;}public TimedAction Fps(double fps) {this.fps = fps;return this;}public TimedAction PlayLocal(Action<double> action){localAction = action;return this;}public TimedAction PlayGlobal(Action<double> action){globalAction = action;return this;}public TimedAction PlayDual(Action<double, double> action){dualAction = action;return this;}public bool IsActive(double elapsedSeconds){return elapsedSeconds >= StartTime &&(EndTime == null || elapsedSeconds <= EndTime.Value + 1 / fps);}public void TryExecute(double elapsedSeconds, double globalProgress, double totalDuration){if (OneTime && elapsedSeconds < StartTime){executed = false;}if (!IsActive(elapsedSeconds)) return;double actionEnd = EndTime ?? totalDuration;double localProgress = (elapsedSeconds - StartTime) / (actionEnd - StartTime);localProgress = Math.Clamp(localProgress, 0, 1);if (OneTime && executed) return;localAction?.Invoke(localProgress);globalAction?.Invoke(globalProgress);dualAction?.Invoke(localProgress, globalProgress);if (OneTime)executed = true;}public void Reset() => executed = false;}// --------------------- 字段 ---------------------private readonly DispatcherTimer timer = new DispatcherTimer();private readonly Stopwatch stopwatch = new Stopwatch();private TimeSpan elapsedOffset = TimeSpan.Zero; // 累计暂停/Seek时间private bool isRunning;// --------------------- 属性 ---------------------[ObservableProperty] private double _speed = 1.0;[ObservableProperty] private double _duration = 10.0;[ObservableProperty] private double _progress;[ObservableProperty] private string _timeText = "[[ stopped ]]";[ObservableProperty] private bool _canPause = false;[ObservableProperty] private bool _canResume = false;[ObservableProperty] private bool _canStop = false;[ObservableProperty] private bool _canSeek = false;[ObservableProperty] private double _fps = 0; private List<TimedAction> Actions { get; } = new();public event Action? AnimationCompleted;public AnimationPlayer(){Fps = 60;timer.Tick += (_, __) => UpdateProgress();}partial void OnFpsChanged(double value){timer.Interval = TimeSpan.FromMilliseconds(1000 / value);foreach (var action in Actions)action.Fps(value);}// --------------------- 链式添加动作 ---------------------public TimedAction At(double startTime, double? endTime = null){var action = new TimedAction(startTime, endTime).Fps(Fps);Actions.Add(action);return action;}// --------------------- 控制方法 ---------------------public void Start(){stopwatch.Restart();elapsedOffset = TimeSpan.Zero;isRunning = true;foreach (var action in Actions)action.Reset();timer.Start();UpdateStates();}public void Pause(){if (!CanPause) return;stopwatch.Stop();elapsedOffset += stopwatch.Elapsed;isRunning = false;timer.Stop();UpdateStates();}public void Resume(){if (!CanResume) return;stopwatch.Restart();isRunning = true;timer.Start();UpdateStates();}public void Stop(){if (!CanStop) return;isRunning = false;timer.Stop();stopwatch.Reset();elapsedOffset = TimeSpan.Zero;Progress = 0;TimeText = "[[ stopped ]]";foreach (var action in Actions)action.Reset();UpdateStates();}public void Seek(double seconds){if (!CanSeek) return;seconds = Math.Clamp(seconds, 0, Duration);elapsedOffset = TimeSpan.FromSeconds(seconds / Speed);       stopwatch.Restart();UpdateProgress();}// --------------------- 更新方法 ---------------------private void UpdateProgress(){double elapsedSeconds = (stopwatch.Elapsed + elapsedOffset).TotalSeconds * Speed;if (elapsedSeconds >= Duration){elapsedSeconds = Duration;isRunning = false;timer.Stop();AnimationCompleted?.Invoke();}Progress = Math.Clamp(elapsedSeconds / Duration, 0, 1);TimeText = TimeSpan.FromSeconds(elapsedSeconds).ToString(@"hh\:mm\:ss\.fff");foreach (var timedAction in Actions)timedAction.TryExecute(elapsedSeconds, Progress, Duration);UpdateStates();}// --------------------- 状态更新 ---------------------private void UpdateStates(){CanPause = isRunning;CanResume = !isRunning && Progress > 0 && Progress < 1;CanStop = isRunning || (Progress > 0 && Progress < 1);CanSeek = Progress > 0 && Progress < 1; }}

ImageWipe.axaml代码

<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Height="250" Width="300"x:Class="AvaloniaUI.ImageWipe"Title="ImageWipe"><Grid RowDefinitions="auto,auto"><Grid><Image Source="avares://AvaloniaUI/Resources/Images/night.jpg"/><Image Source="avares://AvaloniaUI/Resources/Images/day.jpg" Name="imgDay"/></Grid><Button Grid.Row="1" Content="Start" HorizontalAlignment="Center" Click="Button_Click"/></Grid>
</Window>

ImageWipe.axaml.cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
using Shares.Avalonia;
using System.Net;namespace AvaloniaUI;public partial class ImageWipe : Window
{private readonly AnimationPlayer player = new AnimationPlayer() { Duration = 5 };private GradientStop transparentStop = new GradientStop() { Color = Colors.Transparent };private GradientStop visibleStop = new GradientStop() { Color = Colors.Black };public ImageWipe(){InitializeComponent();player.At(0).PlayLocal(p =>{transparentStop.Offset = p;visibleStop.Offset = p + 0.2;imgDay.OpacityMask = new LinearGradientBrush{StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),EndPoint = new RelativePoint(1, 0, RelativeUnit.Relative),GradientStops = new GradientStops { transparentStop, visibleStop }};});}private void Button_Click(object? sender, RoutedEventArgs e){player.Start();}
}

运行效果

 

image

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/915753.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实用指南:科研绘图Origin百度云盘下载与安装指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

大庆免费网站建设开发建设网站需要什么人才

自动接收图片并上传到服务器&#xff0c;仅适用企业微信应用 前言 WorkTool企微机器人可以接收客户群的消息&#xff0c;但接收图片一直是个问题&#xff0c;前面也介绍过两种图片接收方案&#xff0c;但都会影响运行效率&#xff0c;并且不能达到100%的图片接收率&#xff0…

题解:P8067 [BalkanOI 2012] balls

题意 给出一个长为 \(n\) 的序列,让你选择一段长度 \(\ge 2\) 区间内所有值变为区间右或左端点的值,最大化操作后的权值和。 思路 以第一问为例,选择一段区间 \((l,r]\) 后权值和的变化量为: \[(r-l)\times a_r-(s…

题解:P8300 [COCI 2012/2013 #2] INSPEKTOR

题意 要求维护一个直线序列,支持以下操作:操作 \(1\),在 \(K\) 这个位置用一条直线 \(y=Zx+S-Z\times T\) 覆盖这个点原来的直线。 操作 \(2\),查询区间 \([A,B]\) 内的直线在 \(T\) 处的最大值。思路 看到加入直线…

SuperHarness-3D低压柜机电协同设计方案!

【引领未来,智控电气新纪元】 在电力与创新的交响乐章中,利驰软件携手SolidWorks平台,为您匠心打造——低压柜机电协同设计方案,开启电气系统智能化的全新篇章!🌟 智绘蓝图,精准协同 🌟 想象一下,当SolidWo…

详细介绍:.NET驾驭Word之力:打造专业文档 - 页面设置与打印控制完全指南

详细介绍:.NET驾驭Word之力:打造专业文档 - 页面设置与打印控制完全指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family…

vim 入门教学4(命令行模式教学)

vim 入门教学4(命令行模式教学)normal模式下的命令行模式 在vim中除了normal模式能进入命令行模式,也可以在visual模式下进入。两者有所不同visual模式下进入会自动识别范围 normal模式进入命令行模式: 单次进入命令行…

制作个人免费网站展示设计设计学校

在 C 中&#xff0c;operator"" 是用户定义字面量&#xff08;User-Defined Literals&#xff09;的一部分&#xff0c;它允许程序员扩展现有的字面量类型或者创建新的字面量类型。用户定义字面量是在 C11 标准中引入的特性&#xff0c;主要用于提供更易读、更具表达…

使用.NET标准库实现多任务并行处理的详细过程 - 实践

使用.NET标准库实现多任务并行处理的详细过程 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&quo…

下载类网站做多久才有流量郴州网红

4000 还是E2140&#xff1f;两大人气CPU对决互联网 发布时间&#xff1a;2009-04-21 01:31:37 作者&#xff1a;佚名 我要评论今夏攒机&#xff0c;双核处理器无疑是网友们的第一选择。由于Intel和AMD的大力推广&#xff0c;双核处理器的价格目前已经跌到了一个大众消费…

完整教程:Redis的java客户端(SpringDataRedis)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

模型训练中 平均损失值和平均准确率的深入理解

aver_loss 总损失的计算 对于求平均损失来说 需要先求总损失 而求总损失 就需要求一个批次中的损失 对于一个bs来说 损失的计算是利用 loss=criterion(out,labels)计算得出 而criterion 使用的nn.crossentropy 得出来…

一篇了解 Git 运用方式

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

现在有什么网站做设计或编程兼职域名自动更新中

目录 关键词平台说明一、VFB1.1VFB是什么1.1VFB的好处1.2VFB的坏处 二、VFB在ECU内部的描述2.1Components2.2 Port-Interfaces2.3 Port2.4 Compositions 关键词 嵌入式、C语言、autosar、VFB 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语言C&#xff0…

torch.max函数在分类问题中的使用 学习

适用于在pytorch的张量上,求某一维度的最大值。 一般在模型测试阶段,求模型预测输出类别的时候使用。 假设是10分类问题,比如mnist 对于一个批次的输入 images 将它传入net(images) 会得到输出out(bs,10) 但是第二个…

手机p2p网站江西省网站建设公司

教程介绍 旨在降低网络防范黑客的入门门槛&#xff0c;适合所有中小企业和传统企业。罗列常见的攻击手段和防范方法&#xff0c;让网站管理人员都具备基本的保护能力。Python 编程的简单实现&#xff0c;让网络运维变得更简单。各种黑客工具的理论和原理解剖&#xff0c;让人知…

网站开发人力成本电子商务营销方案

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

网站开发实训总结致谢网站源码怎么用

来源&#xff1a;非正式组织概要&#xff1a;在Yann LeCun、Yoshua Bengio和Geoffrey Hinton三巨头nature深度学习综述《deep learning》文章中提到&#xff0c;这段期间神经网络模型被主流的计算机视觉和学术界所抛弃。一、前言深度学习的发展大致分为这么几个学期&#xff1a…

vultr做网站怎么样WordPress登录提醒

redis设置&#xff1a;修改redis服务器的配置文件vim /usr/local/redis/bin/redis.confbind 0.0.0.0 protected-mode no重新启动redissystemctl restart redis.service #重新启动服务注意&#xff1a;服务器的话需要设置安全组开放端口1.导入依赖org.springframework.boot …

react native 国际化 react-i18next 和 i18n,运用高级组件的形式。 - 指南

react native 国际化 react-i18next 和 i18n,运用高级组件的形式。 - 指南2025-09-24 12:57 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x:…