在專案開發中,工具列按鈕往往過於簡陋。參考 macOS Dock 的動態縮放與漸層效果,決定利用 .NET Framework 與 GDI+ 自行開發一個具備滑鼠進入/離開時圖片放大縮小與透明度漸變動畫的自訂按鈕控制項 DynamicImageButton。
傳統做法在滑鼠事件中即時計算透明度與縮放,效能較差。本元件在設定 Image 屬性時,一次性產生 4 種透明度層級的位圖並存入陣列:
private Bitmap[] bmp = new Bitmap[4];
public Bitmap Image
{
get { return bmp[0]; }
set
{
bmp[0] = value;
bmp[1] = ReturnAlpha(value, 60); // 透明度 60
bmp[2] = ReturnAlpha(value, 120); // 透明度 120
bmp[3] = ReturnAlpha(value, 180); // 透明度 180 (最透明)
Draw();
}
}
public static Bitmap ReturnAlpha(Bitmap src, int alpha)
{
Bitmap dst = new Bitmap(src);
for (int x = 0; x < src.Width; x++)
for (int y = 0; y < src.Height; y++)
{
Color c = src.GetPixel(x, y);
if (c.A > 0)
dst.SetPixel(x, y, Color.FromArgb(Math.Max(c.A - alpha, 0), c.R, c.G, c.B));
}
return dst;
}
bmp[0] 為原始圖,bmp[3] 最透明。執行期只需切換陣列索引,無即時運算負擔。
採用雙 Bitmap 交替繪製:
private Bitmap dblBuffer;
private Graphics g, g2;
private void DynamicImageButton_Paint(object sender, PaintEventArgs e)
{
g2 = Graphics.FromImage(dblBuffer);
g2.Clear(BackColor);
// 計算初始繪製矩形 (置中、佔控制項 2/3)
int curX = Width / 6, curY = Height / 6;
int curW = Width * 2 / 3, curH = Height * 2 / 3;
g2.DrawImage(bmp[3], curX, curY, curW, curH);
g.DrawImageUnscaled(dblBuffer, 0, 0);
}
定義四個矩形幀 (a~d) 對應不同大小與透明度:
bmp[0])bmp[1]~bmp[3])使用 Timer 控制幀切換,滑鼠進入 (Enter) 時放大淡入,離開 (Leave) 時縮小淡出:
private enum MousePosition { None, Enter, Leave }
private MousePosition mp = MousePosition.None;
private Timer timer1 = new Timer();
private void timer1_Tick(object sender, EventArgs e)
{
if (mp == MousePosition.Enter)
{
// 放大邏輯:curX--, curY--, curW+=2, curH+=2
// 根據 curX 區間選擇 bmp[0]~bmp[3]
// 達到目標大小停止 Timer
}
else if (mp == MousePosition.Leave)
{
// 縮小邏輯:curX++, curY++, curW-=2, curH-=2
// 同樣依區間切換圖層
// 回到初始大小停止 Timer
}
g2 = Graphics.FromImage(dblBuffer);
g2.Clear(BackColor);
g2.DrawImage(當前bmp, curX, curY, curW, curH);
g.DrawImageUnscaled(dblBuffer, 0, 0);
}
private void DynamicImageButton_MouseEnter(object sender, EventArgs e) { mp = MousePosition.Enter; timer1.Start(); }
private void DynamicImageButton_MouseLeave(object sender, EventArgs e) { mp = MousePosition.Leave; timer1.Start(); }
程式於 Windows XP SP3 + Visual Studio 2005 C# SP1 環境編譯通過。完整原始碼可下載參考。