利用OpacityMask制作打洞效果
起因
项目上存在一个连线功能,在设计的原型中,在连线中间文字上下各有15像素的空白。接手的同事觉得没思路,问我能不能在不影响连线后面的背景情况下解决该问题。我就抽了点时间给他写了个Demo。回家后趁热打铁,重新写了个Demo,添加和完善了些功能。下面是效果图:
代码实现
OpacityMask
在最开始看到效果图的时候,我就想到利用OpacityMask来解决问题。可能这个属性平时很多朋友都没注意到,因为一般情况下用Opacity就足够了。
OpacityMask定义在UIElement中,类型为Brush。仅使用提供的 Brush 的任意 Alpha 通道值。 Brush 呈现内容的其他通道(红色、绿色或蓝色)被忽略。具体来说,在Brush中Alpha通道值为0的地方将为透明,不为0的将显示在UIElement中定义的背景。下面就以Demo中的三个例子简单分享下怎么利用OpacityMask。
矩形空洞
OpacityMask是一个VisualBrush,VisualBrush中有一个三行三列的Grid,Grid中除第二行第二列的单元格外,其余的单元格均用黑色的矩形填充。这样就会在第二行第二列的单元格处形成一个空洞。
主要代码在RectangleHoleConverter中,代码如下:
namespace HoleWithOpacityMask
{
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes; /// <summary>
/// 矩形空洞的转换器
/// </summary>
public class RectangleHoleConverter : IMultiValueConverter
{
/// <summary>
/// 转换成矩形空洞
/// </summary>
/// <param name="values">
/// 转换值列表,第一个表示起始宽度,第二个表示起始高度,
/// 第三个表示总宽度,第四个表示总高度
/// 第五个表示宿主宽度,第六个表示宿主宽度
/// </param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length != 6 || values.HaveNullItem()
|| !values.IsAllInstanceOfType(typeof(double)))
{
return DependencyProperty.UnsetValue;
} var maskStartWidth = (double)values[0];
var maskStartHeight = (double)values[1];
var maskTotalWidth = (double)values[2];
var maskTotalHeight = (double)values[3];
var hostWidth = (double)values[4];
var hostHeight = (double)values[5];
if (hostWidth == 0.0 || hostHeight == 0.0)
{
return null;
} var maskGrid = new Grid { Width = hostWidth, Height = hostHeight }; var opacityStartColumnDefinition = new ColumnDefinition { Width = new GridLength(maskStartWidth) };
var transparentColumnDefinition = new ColumnDefinition { Width = new GridLength(maskTotalWidth) };
ColumnDefinition opacityEndColumnDefinition = new ColumnDefinition();
opacityEndColumnDefinition.Width = new GridLength(1.0, GridUnitType.Star);
maskGrid.ColumnDefinitions.Add(opacityStartColumnDefinition);
maskGrid.ColumnDefinitions.Add(transparentColumnDefinition);
maskGrid.ColumnDefinitions.Add(opacityEndColumnDefinition); var opacityStartRowDefinition = new RowDefinition { Height = new GridLength(maskStartHeight) };
var transparentRowDefinition = new RowDefinition { Height = new GridLength(maskTotalHeight) };
RowDefinition opacityEndRowDefinition = new RowDefinition();
opacityEndRowDefinition.Height = new GridLength(1.0, GridUnitType.Star);
maskGrid.RowDefinitions.Add(opacityStartRowDefinition);
maskGrid.RowDefinitions.Add(transparentRowDefinition);
maskGrid.RowDefinitions.Add(opacityEndRowDefinition); for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if ((i != 1) || (j != 1))
{
Rectangle opacityRectangle = new Rectangle { Fill = Brushes.Black };
Grid.SetRow(opacityRectangle, i);
Grid.SetColumn(opacityRectangle, j);
maskGrid.Children.Add(opacityRectangle);
}
}
} return new VisualBrush(maskGrid);
} public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { Binding.DoNothing };
}
}
}
其中用到了两个扩展方法如下:
namespace HoleTest
{
using System;
using System.Collections.Generic;
using System.Linq; public static class EnumerableExtension
{
/// <summary>
/// 枚举器中是否存在null条目
/// </summary>
/// <typeparam name="T">元素类型</typeparam>
/// <param name="enumerable">元素枚举</param>
/// <returns>存在null条目返回true,否则返回false</returns>
public static bool HaveNullItem<T>(this IEnumerable<T> enumerable)
{
return enumerable.Any(item => item == null);
} /// <summary>
/// 枚举器中是否全为指定类型的实例
/// </summary>
/// <typeparam name="T">元素类型</typeparam>
/// <param name="enumerable">元素枚举</param>
/// <returns>全为指定类型的实例返回true,否则返回false</returns>
public static bool IsAllInstanceOfType<T>(this IEnumerable<T> enumerable, Type type)
{
return enumerable.All(item => type.IsInstanceOfType(item));
}
}
}
椭圆形空洞
OpacityMask是一个DrawingBrush,DrawingBrush是利用GeometryDrawing绘制。而GeometryDrawing中是一个由黑色填充的形状,该形状是在矩形中除去一个椭圆。这样就会在矩形中形成一个空洞。
主要代码在EllipseHoleConverter中,代码如下:
namespace HoleWithOpacityMask
{
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media; /// <summary>
/// 椭圆形空洞的转换器
/// </summary>
public class EllipseHoleConverter : IMultiValueConverter
{
/// <summary>
/// 转换成矩形空洞
/// </summary>
/// <param name="values">
/// 转换值列表,第一个表示起始宽度,第二个表示起始高度,
/// 第三个表示总宽度,第四个表示总高度
/// 第五个表示宿主宽度,第六个表示宿主宽度
/// </param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length != 6 || values.HaveNullItem()
|| !values.IsAllInstanceOfType(typeof(double)))
{
return DependencyProperty.UnsetValue;
} var maskEllipseCenterX = (double)values[0];
var maskEllipseCenterY = (double)values[1];
var maskRadiusX = (double)values[2];
var maskRadiusY = (double)values[3];
var hostWidth = (double)values[4];
var hostHeight = (double)values[5];
if (hostWidth == 0.0 || hostHeight == 0.0)
{
return null;
} var maskRectangle = new RectangleGeometry(new Rect(new Size(hostWidth, hostHeight)));
var maskEllipse = new EllipseGeometry(
new Point(maskEllipseCenterX, maskEllipseCenterY),
maskRadiusX,
maskRadiusY);
var combinedGeometry = Geometry.Combine(maskRectangle, maskEllipse, GeometryCombineMode.Exclude, null);
var drawingBrush = new DrawingBrush(new GeometryDrawing(Brushes.Black, null, combinedGeometry)); return drawingBrush;
} public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { Binding.DoNothing };
}
}
}
图形空洞
其实最常用的还是ImageBrush,因为很多复杂的效果用VisualBrush或者DrawingBrush来实现效果很复杂且不清晰。在上面的Demo中我使用的是一张PNG图片,当然一般也用PNG图标,谁叫它支持透明呢。图片是
XAML代码如下:
<Border Width="180"
Height="180"
Margin="3"
Background="Aquamarine">
<Border Background="LightPink">
<Border.OpacityMask>
<ImageBrush ImageSource="pig.png" />
</Border.OpacityMask>
</Border>
</Border>
容易看出,PNG图片中透明的就真的透明了(直接看到外层Border上级的背景BurlyWood了),不透明的地方就使用了当前Border设置的背景色LightPink。
更多
还可使用线性渐变(LinearGradientBrush)、径向渐变(RadialGradientBrush)实现更多有趣的效果,下图是MSDN中的一个例子
纯色画刷(SolidColorBrush)基本用不到,要么透明,要么不透明,还不如直接设置Opacity。
下载链接
利用OpacityMask制作打洞效果的更多相关文章
- 利用Clip制作打洞效果
起因 如上篇博文所说,连线原型需要在中间文字上下各留15像素的空白.设计师完成原型之后,问我有没有办法实现,我说,我能想到两种实现方式.其中一种就是上篇博文所说的OpacityMask.第二种就是使用 ...
- 利用css3制作毛玻璃的效果
忙里偷闲,最近又在看许多比较酷炫的效果.现在基于jquery的插件比较多,但是很多插件的兼容性不是太好,所以原生的才是王道.在日常当中,毛玻璃已经不常见了,那是一个很久远年代的东西了.诺,下面就是毛玻 ...
- 分享一个利用HTML5制作的海浪效果代码
在前面简单讲述了一下HTML里的Canvas,这次根据Canvas完成了“海浪效果”(水波上升). (O(∩_∩)O哈哈哈~作者我能看这个动画看一下午) 上升水波.gif 动画分析构成:贝塞尔曲线画布 ...
- flash8中利用遮罩制作图片切换效果
http://www.56.com/w73/play_album-aid-8642763_vid-NDY5ODU2Mzg.html
- 利用TabHost制作QQ客户端标签栏效果(低版本QQ)
学习一定要从基础学起,只有有一个好的基础,我们才会变得更加的perfect 下面小编将利用TabHost制作QQ客户端标签栏效果(这个版本的QQ是在前几年发布的)…. 首先我们看一下效果: 看到这个界 ...
- 纯代码利用CSS3 圆角边框和盒子阴影 制作 iphone 手机效果
原文:纯代码利用CSS3 圆角边框和盒子阴影 制作 iphone 手机效果 大家好,我是小强老师. 今天我们看下CSS3最为简单的两个属性. css3给我们带来了很多视觉的感受和变化,以前的图片做的事 ...
- 利用CSS3制作淡入淡出动画效果
CSS3新增动画属性“@-webkit-keyframes”,从字面就可以看出其含义——关键帧,这与Flash中的含义一致. 利用CSS3制作动画效果其原理与Flash一样,我们需要定义关键帧处的状态 ...
- 利用FluidMoveBehavior制作出手机通讯录平滑的效果
最近学习Blend,原来Blend制作动画等效果非常棒.下面演示一下FluidMoveBehavior应用,利用Blend中行为中的FluidMoveBehavior制作出手机通讯录平滑的效果 1.在 ...
- WPF设置VistualBrush的Visual属性制作图片放大镜效果
原文:WPF设置VistualBrush的Visual属性制作图片放大镜效果 效果图片:原理:设置VistualBrush的Visual属性,利用它的Viewbox属性进行缩放. XAML代码:// ...
随机推荐
- Jaxb解析xml准换为javabean
先说下这个的背景吧,前些日子,有个以前的小同事说刚接触webservice,想解析下xml,记得我学的时候还是dom4j,sax的解析方式,最近看别人的代码用的jaxb的方式,觉得注解起来很简练,所以 ...
- guacamole 0.9.9安装与配置
以下命令很多都需要管理权限,建议使用管理员账号执行,遇到问题可以留言. 1.首先需要安装guacamole所需要的依赖库 必需安装的库有:Cairo.libjpeg-turbo.libpng.OSSP ...
- c#多线程生产者消费者(手稿)
屋舍简陋,隔壁的娃娃哭了一晚,心中无恶意纯中性的想,有病就赶紧带孩子去看医生吧,能哭这么久估计孩子真的不舒服.
- C语言位运算详解
位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作运算符.这些运算符只能用于整形操作数,即只能用于带符号或无符号的char.short.int与long类型 ...
- [ javascript New Image() ] New Image() 对象讲解
创建一个Image对象:var a=new Image(); 定义Image对象的src: a.src="xxx.gif"; 这样做就相当于给浏览器缓存了一张图片. 图 ...
- 公司outing选项
Sign up: 2014 Summer Outing 请您从以下三个方案中选择您最感兴趣的一个项目, 如果您不能参加此次summer outing, 请选择"遗憾放弃"- ...
- 使用tinypng优化Android的资源图片
tinypng 是一个支持压缩png和jpg图片格式的网站,通过其独特的算法(通过一种叫“量化”的技术,把原本png文件的24位真彩色压缩为8位的索引演示,是一 种矢量压缩方法,把颜色值用数值123等 ...
- Android Studio 项目代码全部消失--出现原因及解决方法
出现原因,自己把项目地址父层目录文件名修改了,导致原来打开的项目位置不对,代码全部消失.这样就只要关闭项目,打开一下你修改路径下的项目即可.因为原来的项目还在原来的路径下寻找,但是原来的路径发生了改变
- iOS设计模式之工厂方法模式
工厂方法模式 基本理解 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 简单工厂的最大优点就是工厂类中包含了必要的逻辑判断,根据客户端的选择 ...
- Mac OS X上安装 Ruby运行环境
环境 对于新入门的开发者,如何安装 Ruby和Ruby Gems 的运行环境可能会是个问题,本页主要介绍如何用一条靠谱的路子快速安装 Ruby 开发环境.此安装方法同样适用于产品环境! 系统需求 ...