棒棒牛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2136|回复: 7

[交流] WPF实现类似于Flash的遮罩(Mask)效果 [复制链接]

版主

WPF_1.5_ray

Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7

游币
259
金币
543
经验
1690
积分
2175
帖子
428

2011 年度优秀版主 2010 年度优秀版主

发表于 2010-8-18 14:39:22 |显示全部楼层
松德提出的问题,如何像Flash当中一样,能把WPF中的Control作为一个遮罩元件。
要求的效果:
1、使用控件作为遮罩元件。
2、遮罩的颜色可以混合。
3、使用Blend,而不要写代码。

WPF的控件默认提供一个Clip属性,可以实现类似的效果。但是Clip是一个Geometry,如果遮罩元件本身要求有动画之类的,Clip就无法实现,或者很难实现。

研究了一下,可以利用WPF中的OpacityMask来做。OpacityMask合成的原则是,有颜色的地方就显示,同时按照透明度来进行混合。因此,我们把被遮罩对象的OpacityMask设置为遮罩元件的VisualBrush即可。但是,注意顾名思义,该属性仅仅只是改变控件可见的程度,而无法混合OpacityMask本身的颜色。

因此,无法直接实现松德要求的效果。

考虑间接的实现,把遮罩拆成两步,一步是利用OpacityMask进行遮罩,一步是实现混合。
整体结构如下:
层次结构.png

MaskLayer是一个Grid,用来放置提供VisualBrush的遮罩元素。MaskLayer本身是Hidden的,而当中的遮罩元素是Visible的,这样我们就不会直接看见遮罩元素,同时遮罩元素能提供有效的VisualBrush。
BrushLayer是一个Rectangle,用来提供混合的颜色。
示例中,MaskLayer和BrushLayer都被设置成HitTestVisible = false,这个看需求。

首先,我们在MaskLayer中放置一个TextBlock,然后通过Blend提供的工具,调用菜单Tools->Make Brush Resource->Make VisualBrush Resource来创建一个VisualBrush。

Image_MaskTarget是一个Image控件,也就是被遮罩的元素。我们将它的OpacityMask指定为刚才创建的VisualBrush,这时候应该已经能看到Image仅仅显示出TextBlock中Text所限定的区域了。

接着,我们设置MaskLayer(即 Rectangle)的Fill为我们想要的颜色,这里设定是一个蓝色,并且透明度是30%,接下来,将MaskLayer的OpacityMask也指定成TextBlock的VisualBrush,否则会显示整个MaskLayer的颜色。
MaskLayer.png


最后,做个TextBlock的动画。
123.gif


WpfMask.zip (777.24 KB, 下载次数: 84)

但是,这种方式似乎有个缺陷,就是没法对TextBlock的位置做动画
What is real?

V4

懒散的牛

Rank: 4Rank: 4Rank: 4Rank: 4

游币
75
金币
171
经验
568
积分
717
帖子
161
发表于 2010-8-18 14:41:31 |显示全部楼层
占领沙发

V1

Rank: 1

游币
100
金币
29
经验
15
积分
19
帖子
6
发表于 2010-8-18 14:43:57 |显示全部楼层
太快了吧,我都没沙发

版主

WPF_1.5_ray

Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7

游币
259
金币
543
经验
1690
积分
2175
帖子
428

2011 年度优秀版主 2010 年度优秀版主

发表于 2010-8-18 14:54:17 |显示全部楼层
这种方式没法改变Mask的位置,大家有没有更好的办法?
What is real?

V1

Rank: 1

游币
100
金币
29
经验
15
积分
19
帖子
6
发表于 2010-8-18 15:05:27 |显示全部楼层
1.png

为什么MARK后的效果大小并非与实现的TEXTBLOCK一致呢?

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
        x:Class="WpfMask.Window1"
        x:Name="Window"
        Title="Window1"
        UseLayoutRounding="True"
        Width="640" Height="480">
        <Window.Resources>
                <VisualBrush x:Key="textBlock" Visual="{Binding ElementName=textBlock}"/>
        </Window.Resources>

        <Grid x:Name="LayoutRoot">
                <Rectangle Fill="Blue" Margin="94,194,81,220" Stroke="Black" OpacityMask="{DynamicResource textBlock}"/>
                <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="2,203,0,224" TextWrapping="Wrap" Text="TextBlock" FontSize="21.333" d:LayoutOverrides="Height"/>
        </Grid>
</Window>

V1

Rank: 1

游币
100
金币
29
经验
15
积分
19
帖子
6
发表于 2010-8-18 17:04:11 |显示全部楼层
悲剧的是VISUALBRUSH在SLIVERLIGHT都没有,这样的效果在IE是实现就更无望了

版主

WPF_1.5_ray

Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7

游币
259
金币
543
经验
1690
积分
2175
帖子
428

2011 年度优秀版主 2010 年度优秀版主

发表于 2010-8-18 20:55:44 |显示全部楼层
那就只好搞个Clip了
What is real?

V1

Rank: 1

游币
100
金币
0
经验
14
积分
18
帖子
7
发表于 2010-10-9 18:45:18 |显示全部楼层
确实不错,好好看看
您需要登录后才可以回帖 登录 | 注册

bbniu.com (湘ICP备06008909号)  

GMT+8, 2012-2-6 10:12

Copyright © 2009-2011 bbniu.com. All Rights Reserved.

回顶部