【问题标题】:How to make frosted glass effect in Windows 10 Universal App? [closed]如何在 Windows 10 Universal App 中制作磨砂玻璃效果? [关闭]
【发布时间】:2015-11-06 09:31:15
【问题描述】:

那么,如何使用 C# & XAML 实现这样的效果呢?

【问题讨论】:

  • 到目前为止你有没有尝试过?一些代码或任何您尝试过但没有成功的代码?
  • 我在网上找这样的东西,但是有例子模糊了图像,但不重叠,但它们与 Windows 10 无关,所以我什至不知道在哪里开始。和知道的人帮助我,我写到这里,但不是为你写的蔑视回应。

标签: c# uwp windows-store-apps windows-10 win-universal-app


【解决方案1】:

您应该查看 Win2D 类并在其中查看 Canvas Effects - 有一个 GaussianBlurEffect 可能会有所帮助。这是参考: http://microsoft.github.io/Win2D/html/N_Microsoft_Graphics_Canvas_Effects.htm 对于 GaussianBlurEffect: http://microsoft.github.io/Win2D/html/T_Microsoft_Graphics_Canvas_Effects_GaussianBlurEffect.htm 包括一些 C# 代码示例。

补充:如果你想知道如何使用win2D,我刚刚找到了一个方便的教程(我现在正在关注它:))http://blogs.msdn.com/b/uk_faculty_connection/archive/2014/09/05/win2d.aspx

【讨论】:

  • 没用过Win2D类所以不能直接说。但是从性能的角度来看,是否想知道使用 SetWindowCompositionAttribute 的方法可能更好或更坏?我知道它使用 Interop,这可能是对 Win2D 的投票,但也似乎非常......原生,可以这么说 :) (你可能听说过,我自己没有测试过,只要知道,如果你还没有t 自己测试过,我明天会尝试并在这里发布我的发现)示例:withinrafael.com/…(对“在你的脸上”标志感到抱歉)
【解决方案2】:

自从 iOS 7 引入了磨砂玻璃以来,我一直在尝试创建类似的东西。现在多亏了 Win2D,在 WinRT 中创建类似的效果要简单得多。

首先,您需要从 NuGet 获取 Win2D.uwp 包。

我们的想法是根据图像源创建一个GaussianBlurEffect,并将其放在另一个白色颜色的蒙版上,以模仿毛玻璃的外观。

要准备好GaussianBlurEffect,您需要从 Win2D 库创建一个 xaml 控件CanvasControl。所以 UI 结构是这样的 -

<Grid x:Name="ImagePanel2" Width="356" Height="200" Margin="0,0,0,40" VerticalAlignment="Bottom">
    <Image x:Name="Image2" Source="Assets/Food.jpg" Stretch="UniformToFill" />
    <Grid x:Name="Overlay" ManipulationMode="TranslateX" ManipulationStarted="Overlay_ManipulationStarted" ManipulationDelta="Overlay_ManipulationDelta" ManipulationCompleted="Overlay_ManipulationCompleted" RenderTransformOrigin="0.5,0.5">
        <Grid.Clip>
            <RectangleGeometry x:Name="Clip" Rect="0, 0, 356, 200" />
        </Grid.Clip>
        <Rectangle x:Name="WhiteMask" Fill="White" />
        <Xaml:CanvasControl x:Name="Canvas" CreateResources="Canvas_CreateResources" Draw="Canvas_Draw" />
    </Grid>
    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Frosted Glass" VerticalAlignment="Top" Foreground="#FF595959" Margin="12,12,0,0" FontWeight="Light" FontSize="26.667" FontStyle="Italic" TextLineBounds="Tight" />
</Grid>

注意我已经为Overlay 元素创建了一个Clip,因为我需要在平移它时减小Rect 的第三个参数(即宽度)向左移动以产生Overlay 与我的手指一起滑动的错觉。

后面的代码非常简单 -

void Canvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
{
    args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
}

async Task CreateResourcesAsync(CanvasControl sender)
{
    // give it a little bit delay to ensure the image is load, ideally you want to Image.ImageOpened event instead
    await Task.Delay(200);

    using (var stream = new InMemoryRandomAccessStream())
    {
        // get the stream from the background image
        var target = new RenderTargetBitmap();
        await target.RenderAsync(this.Image2);

        var pixelBuffer = await target.GetPixelsAsync();
        var pixels = pixelBuffer.ToArray();

        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)target.PixelWidth, (uint)target.PixelHeight, 96, 96, pixels);

        await encoder.FlushAsync();
        stream.Seek(0);

        // load the stream into our bitmap
        _bitmap = await CanvasBitmap.LoadAsync(sender, stream);
    }
}

void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
    using (var session = args.DrawingSession)
    {
        var blur = new GaussianBlurEffect
        {
            BlurAmount = 50.0f, // increase this to make it more blurry or vise versa.
            //Optimization = EffectOptimization.Balanced, // default value
            //BorderMode = EffectBorderMode.Soft // default value
            Source = _bitmap
        };

        session.DrawImage(blur, new Rect(0, 0, sender.ActualWidth, sender.ActualHeight),
            new Rect(0, 0, _bitmap.SizeInPixels.Width, _bitmap.SizeInPixels.Height), 0.9f);
    }
}

void Overlay_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
    // reset the inital with of the Rect
    _x = (float)this.ImagePanel2.ActualWidth;
}

void Overlay_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    // get the movement on X axis
    _x += (float)e.Delta.Translation.X;

    // keep the pan within the bountry
    if (_x > this.ImagePanel2.ActualWidth || _x < 0) return;

    // we clip the overlay to reveal the actual image underneath
    this.Clip.Rect = new Rect(0, 0, _x, this.ImagePanel2.ActualHeight);
}

void Overlay_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
    // reset the clip to show the full overlay
    this.Clip.Rect = new Rect(0, 0, this.ImagePanel2.ActualWidth, this.ImagePanel2.ActualHeight);
}

您可以进一步调整 BlurAmount 属性以及不透明度图 (0.9f) 以获得您想要的确切效果。

还要注意,将来可能会有另一种(更好的?)方法来做到这一点。如果new Composition API 在以后的版本中确实支持GaussianBlurEffect,我会更新答案。

您可以从此 GitHub repo 找到当前的工作示例。我在这里附上了一张图片来展示它的样子。 :)

【讨论】:

  • 哦,不错的决定,谢谢,但这只是我需要的一半。那么动态内容有什么选择吗?所以,我们在那里有主页和动态框架,比如这里:&lt;Grid&gt;&lt;SplitView&gt;&lt;SplitView.Pane&gt;&lt;Grid&gt;overlay code, content&lt;/SplitView.Pane&gt;&lt;Frame x:Name="dyn cont" /&gt;&lt;/SplitView&gt;&lt;/Grid&gt; 刚才它适用于背景图像。
  • 据我了解,这完全取决于图像,即:_bitmap = await CanvasBitmap.LoadAsync(sender, "here"); 那么,我们可以发送当前帧的屏幕吗?还是有别的方法?
  • @SnakeAce, LoadAsync 也接受IRandomAccessStream。因此,您可以使用RenderTargetBitmap 从 UI 上的任何UIElement 获取位图,然后将其转换为InMemoryRandomAccessStream。请参阅我的更新答案。
  • 了解如何应用更高级的模糊here
猜你喜欢
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 2017-09-18
  • 2012-07-21
  • 2019-04-16
  • 1970-01-01
  • 1970-01-01
  • 2013-06-10
相关资源
最近更新 更多