文: 流暢設計 Fluent Design System 中的光照效果 RevealBrush,WPF 也能模拟實作啦!
版權聲明:本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協定進行許可。歡迎轉載、使用、重新釋出,但務必保留文章署名呂毅(包含連結:http://blog.csdn.net/wpwalter/),不得用于商業目的,基于本文修改後的作品務必以相同的許可釋出。如有任何疑問,請與我聯系([email protected])。 https://blog.csdn.net/WPwalter/article/details/79827611
UWP 才能使用的流暢設計效果好驚豔,寫新的 UWP 程式可以做出更漂亮的 UI 啦!然而古老的 WPF 項目也想解解饞怎麼辦?
于是我動手實作了一個!
迫不及待看效果

▲ 是不是很像 UWP 中的
RevealBorderBrush
?
不止是效果像,連 XAML 寫法也像:
<Border BorderThickness="1" Margin="50,34,526,348">
<Border.BorderBrush>
<demo:RevealBorderBrush />
</Border.BorderBrush>
</Border>
<Border BorderThickness="1" Margin="50,76,526,306">
<Border.BorderBrush>
<demo:RevealBorderBrush Color="White" FallbackColor="Gray" />
</Border.BorderBrush>
</Border>
▲ 模拟得很像的 RevealBorderBrush 的 XAML 寫法
當然,視窗背景那張圖是直接用的高斯模糊效果,并不是亞克力 Acrylic 效果。鑒于那張被模糊得看不清的圖是我自己畫的,是以我一定要單獨放出來給大家看��!
▲ 我自己畫的圖,不忍直視,隻好模糊掉作為背景了
話不多說看源碼
UWP 裡的 CompositionBrush 是用一個 ShaderEffect 做出所有控件的所有效果的。正如
叛逆者在
如何評價微軟在 Build 2017 上提出的 Fluent Design System? - 知乎一文中說的,隻需要極少的計算量就能完成。
不過 Win32 視窗并沒有得到眷戀,是以我隻好自己實作。但限于隻能使用 WPF 内建機制,故性能上當然不能比了。但在小型項目的局部用用還是非常不錯的——尤其是個人項目!不過話說現在個人項目誰還用 WPF 呢 (逃
思路是畫一個徑向漸變,即
RadialGradientBrush
,然後當滑鼠在視窗内移動時,改變徑向漸變的漸變中心為滑鼠所在點。
以下是全部源碼。不要在意基類啦!WPF 不讓我們實作自己的 Brush,是以隻好用 MarkupExtension 繞道實作了。
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
namespace Walterlv.Demo
{
/// <summary>
/// Paints a control border with a reveal effect using composition brush and light effects.
/// </summary>
public class RevealBorderBrushExtension : MarkupExtension
{
/// <summary>
/// The color to use for rendering in case the <see cref="MarkupExtension"/> can't work correctly.
/// </summary>
public Color FallbackColor { get; set; } = Colors.White;
/// <summary>
/// Gets or sets a value that specifies the base background color for the brush.
/// </summary>
public Color Color { get; set; } = Colors.White;
public Transform Transform { get; set; } = Transform.Identity;
public Transform RelativeTransform { get; set; } = Transform.Identity;
public double Opacity { get; set; } = 1.0;
public double Radius { get; set; } = 100.0;
public override object ProvideValue(IServiceProvider serviceProvider)
{
// 如果沒有服務,則直接傳回。
if (!(serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget service)) return null;
// MarkupExtension 在樣式模闆中,傳回 this 以延遲提供值。
if (service.TargetObject.ToString().EndsWith("SharedDp")) return this;
if (!(service.TargetObject is FrameworkElement element)) return this;
if (DesignerProperties.GetIsInDesignMode(element)) return new SolidColorBrush(FallbackColor);
var window = Window.GetWindow(element);
if (window == null) return this;
var brush = CreateBrush(window, element);
return brush;
}
private Brush CreateBrush(Window window, FrameworkElement element)
{
var brush = new RadialGradientBrush(Colors.White, Colors.Transparent)
{
MappingMode = BrushMappingMode.Absolute,
RadiusX = Radius,
RadiusY = Radius,
Opacity = Opacity,
Transform = Transform,
RelativeTransform = RelativeTransform,
};
window.MouseMove += OnMouseMove;
window.Closed += OnClosed;
return brush;
void OnMouseMove(object sender, MouseEventArgs e)
{
var position = e.GetPosition(element);
brush.GradientOrigin = position;
brush.Center = position;
}
void OnClosed(object o, EventArgs eventArgs)
{
window.MouseMove -= OnMouseMove;
window.Closed -= OnClosed;
}
}
}
}