[WPF] 抄抄超強的蘋果官網滾動文字特效實現

1. 前言

今天 ChokCoco 大佬發布了一篇部落格 超強的蘋果官網滾動文字特效實現,iPhone 我是買不起的,但不妨礙我對抄特效感興趣,正好我這周安排的工作已經完成了,於是有空練練手實現了一個 WPF 版本。最終效果如下:

2. 原理

這個特效的原理在 ChokCoco 的文章里已經講解得很詳細了,簡單來說只有兩部:

1,在前面固定一個黑色的圖層,但是裁剪出文字的形狀。
2,在背景放一個漸變色的圖層,滾動頁面時透過前面圖層的鏤空部分觀察到這個移動的漸變色的圖層,隨著頁面的向下滾動,整個文字從無到出現,再經歷一輪漸變色的變化,最後再逐漸消失。

所以我們主要做的有兩樣:一個鏤空的圖層,一個漸變的圖層。

3. 使用自定義 Effect 實現文字任意形狀的鏤空

之前用自定義 Effect 玩 InnerShadow 時實現了一個 ClipEffect,它就實現了鏤空(正確來說是裁剪)的功能,這次正好用得上。

ClipEffect 的程式碼很簡單,就只是幾行,關鍵的功能是用 input 的Alpha 通道減去 blend 的 Alpha 通道作為結果輸出:

sampler2D blend : register(s1);

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 inputColor = tex2D(input, uv);
    float4 blendColor = tex2D(blend, uv);
    float4 resultColor = 0;
    float opacity = inputColor.a - blendColor.a;
    resultColor.rgb = inputColor.rgb * opacity;
    resultColor.a = opacity;

    return resultColor;
}

使用的時候,在一個不透明的元素上應用 ClipEffect,將它的 Blend 屬性設置為要裁剪的形狀的 VisualBrush,例如下面的程式碼里使用了文字作為 VisualBrush,最終在 Grid 上裁剪出一段文字的鏤空:

<Grid Background="Black">
    <Grid.Effect>
        <effects:ClipEffect>
            <effects:ClipEffect.Blend>
                <VisualBrush Stretch="None" Visual="{Binding ElementName=TextElement}" />
            </effects:ClipEffect.Blend>
        </effects:ClipEffect>
    </Grid.Effect>
</Grid>

4. 漸變

漸變大部分就更簡單了,抄 ChokCoco 大佬的就是了。在 CSS 中,一個帶點傾斜角度的漸變只需要一行 CSS 定義:

linear-gradient(-3deg, #000, #000 25%, #ffb6ff, #b344ff, #000 75%, #000);

而到了 XAML 中就複雜多了(當然,如果真的有必要省那麼幾行的話也可以自定義擴展、自定義行為之類的簡化寫法):

<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
    <LinearGradientBrush.RelativeTransform>
        <TransformGroup>
            <ScaleTransform CenterX="0.5" CenterY="0.5" />
            <SkewTransform CenterX="0.5" CenterY="0.5" />
            <RotateTransform Angle="-3" CenterX="0.5" CenterY="0.5" />
            <TranslateTransform />
        </TransformGroup>
    </LinearGradientBrush.RelativeTransform>
    <GradientStop Color="#000" />
    <GradientStop Offset=".25" Color="#000" />
    <GradientStop Offset=".416" Color="#ffb6ff" />
    <GradientStop Offset=".583" Color="#b344ff" />
    <GradientStop Offset=".75" Color="#000" />
    <GradientStop Offset="1" Color="#000" />
</LinearGradientBrush>

上面的 XML 定義了一個漸變的 LinearGradientBrush,這個 LinearGradientBrush 需要旋轉 -3 度。有兩種方式可以實現 LinearGradientBrush 的旋轉,其中一種是 改變 StartPoint 和 EndPoint,但這種方式計算上比較麻煩,這裡採用了另一種方式,即直接改變 LinearGradientBrush.RelativeTransform。最後呈現的效果如下:

5. 最後

有了上面這兩個圖層,接下來結合它們:將鏤空的圖層固定在前面,漸變色的圖層放進 ScrollViewer,滾動 ScrollViewer 時讓這個漸變圖層滑過鏤空的部分,一個酷炫的效果就完成了。

最近無論工作還是學習都很飽和,正好今天告一段落可以摸一下魚,感謝 ChokCoco 大佬一直發掘和實現各種有趣的特效,讓我摸魚摸得更有意義。

6. 源碼

//github.com/DinoChan/wpf_design_and_animation_lab