利用 Form.Opacity (0.0~1.0) 搭配 Timer 定期調整透明度,即可實現視窗淡入/淡出動畫。本文提供可重用的基底類別 FadeForm。
Opacity = 0 → 每 Tick 增加 InSpeed/100 → 達 1.0 停止 Timer。Opacity = 1 → 每 Tick 減少 OutSpeed/100 → 達 0.0 關閉視窗並停止 Timer。InSpeed/OutSpeed 範圍 1~100,數值越大越快。
public class FadeForm : Form
{
private readonly Timer _timer = new Timer { Interval = 20 };
private int _state; // 0=淡入, -1=淡出
public double InSpeed { get; set; } = 10;
public double OutSpeed { get; set; } = 10;
public FadeForm()
{
_timer.Tick += Timer_Tick;
this.Load += (s, e) => { _state = 0; Opacity = 0; _timer.Start(); };
}
private void Timer_Tick(object sender, EventArgs e)
{
if (_state >= 0) // 淡入
{
Opacity += InSpeed / 100.0;
if (Opacity >= 1) { Opacity = 1; _timer.Stop(); }
}
else // 淡出
{
Opacity -= OutSpeed / 100.0;
if (Opacity <= 0) { _timer.Stop(); Close(); }
}
}
public new void Close() // 淡出關閉
{
if (Opacity > 0) { _state = -1; _timer.Start(); }
else base.Close();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (Opacity > 0 && e.CloseReason != CloseReason.WindowsShutDown)
{
e.Cancel = true;
Close(); // 觸發淡出
}
else base.OnFormClosing(e);
}
}
// 直接繼承
public class MyDialog : FadeForm
{
public MyDialog() { InSpeed = 20; OutSpeed = 15; InitializeComponent(); }
}
// 或在現有 Form 中組合
var form = new Form();
var fade = new FadeHelper(form) { InSpeed = 15, OutSpeed = 15 };
form.ShowDialog();
| 需求 | 方案 |
|---|---|
| 非線性動畫 (Easing) | 引入 double easing(double t) => 1 - Math.Pow(1 - t, 3) (EaseOutCubic) 計算每幀 Opacity |
| 高 DPI 縮放閃爍 | 設定 SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true) |
| 跨平台 (WPF/MAUI) | WPF 使用 DoubleAnimation 作用於 Window.Opacity;MAUI 使用 View.FadeTo |
| 效能 | Timer Interval 15~30ms 即可;避免在 Tick 中做重運算 |
Opacity 需視窗啟用分層視窗 (WS_EX_LAYERED),Windows 2000+ 原生支援。TransparencyKey 或非矩形區域,淡出邊緣可能出現鋸齒。OnFormClosing 邏輯防止重複觸發。