在这篇文章中我将要讨论在Windows Phone 7中的Opacity Mask。基本上Opacity mask的功能是让一个element的某部分能够透明或者能偶部分透明。你只需将一个element或者Visual(每一个UI元素都有OpacityMask这个公有属性)的OpacityMask属性设置成一个Brush就能创建Opacity Mask。这个Brush就能隐射到element或者Visual上去,每一个画刷像素的不透明度值被用来确定element上每个相应像素的最终不透明度值。
当在编写WP7应用程序的时候,经常要做的一个任务是保证你的程序在明暗两种主题下都能尽可能看起来一致(这个是Windows Phone 7 应用程序认证要求中的一项要求)。大多数的应用中,开发者都是在使用图标,图片,图片按钮等等...那么我们怎么能够使用一套图标/图片,但在不同主题下还能和当前的主题颜色保持一致性呢?总的来说最简单(但绝不是最好的)的方法就是使用两套图标,分别在明暗两种主题里使用。但更好的解决方法是使用一套图标/图片外加OpacityMask。
根据最新版本的Windows Phone 7 应用程序认证要求(这里是连接):
5.5 内容验证
The application content (e.g. text, visual elements) must be visible and legible regardless of the phone theme. For example, if the phone theme changes from black background to white background, the text and visual elements of your application must be visible or legible.
应用程序的内容(例如:文本,可视化的元素)不管在哪种手机主题下都要醒目和清晰。举个例子,如果把手机主题从黑色背景更改为白色背景,这时文本和可视化元素一定要能够清晰醒目的呈现。
所以在明暗两种主题下测试你的应用程序是很重要的一个环节。如果你遗忘了这个步骤,那么你的应用就有可能在上市场的时候被微软驳回。
在明暗主题下测试
很多开发者犯的很常见的错误就是忘记在亮/暗主题下分别测试他们开发的程序。在模拟器中默认情况下是在黑色主题,因此在测试阶段就很容易忽略了主题切换。不在不同的主题下测试的后果是一些元素被背景色吞没甚至是看不见了。许多UI元素支持系统范围的主题配置,但是有一些不支持。尤其是自定义编译的控件和图片/图标。在两种主题下测试你的程序将保证你的程序能够清晰的呈现。
什么是OpacityMask?
根据官方文档一个opacity mask的主要功能是映射它的内容到elemet或者visual。如果给定画刷每个像素的alpha通道被用来确定elements和visual对应像素的不透明度;画刷实际颜色不忽略了。如果画刷的部分是透明的,elements和visual相应的部分也会变成透明的。如果给定画刷是不透明的,但elements和visual相应部分的透明度不会改变。被opacity mask指定的不透明度最终是结合了element或者visual的任何关于不透明度的设置。例如,如果一个元素有着25%的不透明度,同时opacity mask被设置成了从完全不透明到完全透明的转换,最后的呈现结果是这个元素是25%的不透明到完全透明的变换。
如果想要了解更多关于OpacityMask的信息请查看MSDN文档
同样你也可以在Expression Blend或者只是在Visual Studio里编写一些XAML代码添加一个Opacity Mask。
OpacityMask and Expression Blend
在blend里面给任何element添加Opacity Mask是在Windows Phone7应用程序里最简单的方法。你要做的只是使用可视话设计器(visual designer ),当然你不需要添加任何的自定义代码。但是这种方式最大的缺点就是最后得到的代码中会有很多无用的Margin,Padding,Height等等被Expression Blend自动添加的设置。
下面我通过一个小示例来了解在Blend里添加Opacitu Mask的步骤。首先我们添加一些两套(黑和白)的图标到工程中来。
1.给Rectangle添加Opacity Mask
在这个例子中我们要创建一个绿色的矩形,而且我们要按照下面的步骤给它添加Opacity Mask:
● 选中新建的矩形并选择属性Tab页
● 在搜索框内输入Opacity Mask
● 选中OpacityMask 修改它的Tile Brush选项
● 设置ImageSource为你想要的图片
● 这时,你就能够看到效果了
2. 使用明暗两种图标给一个按钮添加OpacityMask
在这个例子中我们要创建一个按钮,通过以下步骤设置他的OpacityMask,那么这个按钮的图标不管是在暗色或者是亮色主题下都能比较稳定的显示:
● 选中新创建的按钮并选择属性Tab页
● 在搜索栏里输入OpacityMask
● 选中OpacityMask 修改它的Tile Brush选项
● 设置ImageSource为你想要的图片
● 在属性Tab页的Background选区点击 Brush资源Tab
● 选择PhoneContrastBackgroundBrush 画刷
● 这时你就能够看到效果了
注意:别忘了设置背景色否则你将看不到你创建的按钮。
OpacityMask and VisualStudio
下面的OpcaityMask在代码里的样子。(我这里是优化了一下代码,删除了不必要的Margin,Padding等等这些)。实际上每一个UI元素都有OpacityMask这个属性,它能够被赋值为一个画刷实例。
1.给矩形添加OpacityMask
<Rectangle Fill="#FF2CA90A" Height="116" Stroke="Black" Width="115"> <Rectangle.OpacityMask> <ImageBrush Stretch="Fill" ImageSource="icons/appbar.delete.rest.png"/> </Rectangle.OpacityMask> </Rectangle>
2.使用明暗两种图标给按钮添加OpacityMask
<Button Height="87" Width="145" Background="{StaticResource PhoneContrastBackgroundBrush}"> <Button.OpacityMask> <ImageBrush Stretch="Fill" ImageSource="icons/appbar.feature.video.rest.png"/> </Button.OpacityMask> </Button> <Button Height="87" Width="145" Background="{StaticResource PhoneContrastBackgroundBrush}"> <Button.OpacityMask> <ImageBrush Stretch="Fill" ImageSource="icons/appbar.feature.email.rest.png"/> </Button.OpacityMask> </Button>
3.使用暗主题给椭圆添加OpacityMask
在这个例子中我们会在一个Grid里创建两个椭圆,但是只给第二个椭圆添加OpacityMask。最终的目的是要创建圆形图像按钮。
<Grid Width="72" Height="72" Margin="0,-10"> <Ellipse Stroke="{StaticResource PhoneBorderBrush}" StrokeThickness="{StaticResource PhoneBorderThickness}" Fill="{StaticResource PhoneSemitransparentBrush}" Margin="{StaticResource PhoneTouchTargetOverhang}" /> <Ellipse Fill="{StaticResource PhoneForegroundBrush}" Margin="{StaticResource PhoneTouchTargetOverhang}"> <Ellipse.OpacityMask> <ImageBrush ImageSource="icons/appbar.feature.email.rest.png"/> </Ellipse.OpacityMask> </Ellipse> </Grid>
4.在后台代码里创建OpacityMask.
前面三个例子都是使用XAML代码实现,在这个示例里我们将在后台代码里实现OpacityMask。
Button btn = new Button(); btn.Height = 100; btn.Width = 100; btn.Background = Application.Current.Resources["PhoneContrastBackgroundBrush"] as SolidColorBrush; ImageBrush image = new ImageBrush(); image.ImageSource = new BitmapImage( new Uri("icons/appbar.feature.email.rest.png", UriKind.Relative)); image.Stretch = Stretch.Fill; btn.OpacityMask = image; this.ContentPanel.Children.Add(btn);
5.带有VisualState的主题友好的按钮.
在这个例子中我们将要创建一个带有VisualState主题友好的按钮,我们添加了一个OpacityMask到这个按钮的ControlTemplate里。
<Style x:Key="SampleIconButton" TargetType="Button"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/> <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/> <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/> <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/> <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid Background="Transparent"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ContentArea"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BackgroundBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="BackgroundBrush" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}"> <Grid x:Name="ContentArea" OpacityMask="{TemplateBinding Content}" Background="{TemplateBinding Foreground}"/> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Button Style="{StaticResource SampleIconButton}" Height="100" Width="100"> <ImageBrush ImageSource="icons/appbar.delete.rest.png" Stretch="None"/> </Button>
这里是最后的呈现效果的截图
你可以在这里下载源码:OpacityMask.zip
希望对你有帮助,如果有什么问题可以留言讨论。
原文地址:http://www.windowsphonegeek.com/articles/Creating-theme-friendly-UI--in-WP7-using-OpacityMask