利用Clip制作打洞效果
起因
如上篇博文所说,连线原型需要在中间文字上下各留15像素的空白。设计师完成原型之后,问我有没有办法实现,我说,我能想到两种实现方式。其中一种就是上篇博文所说的OpacityMask。第二种就是使用Clip了。下面是效果图:

代码实现
Clip
Clip定义在UIElement中,类型为Geometry 。MSDN中的解释是获取或设置用于定义元素内容边框的几何图形。实际上不光可以在边框处留住空白,在UI元素里面留出空白也是可以的,只要定义好相关的形状。
矩形空洞
在一个大矩形中去除一个小矩形就行了。
主要代码在RectangleHoleConverter中,代码如下:
namespace HoleWithClip
{
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media; /// <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 maskRectangle = new RectangleGeometry(new Rect(new Size(hostWidth, hostHeight)));
var maskEllipse = new RectangleGeometry(new Rect(
new Point(maskStartWidth, maskStartHeight),
new Size(maskTotalWidth, maskTotalHeight)));
var combinedGeometry = Geometry.Combine(maskRectangle, maskEllipse, GeometryCombineMode.Exclude, null); return combinedGeometry;
} 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));
}
}
}
椭圆形空洞
跟矩形空洞类似,在大的矩形中间排除一个椭圆。
主要代码在EllipseHoleConverter中,代码如下:
namespace HoleWithClip
{
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); return combinedGeometry;
} public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { Binding.DoNothing };
}
}
}
不规则空洞
我们各种Shape中最常用的是Path,因为许多复杂的效果能够在设计工具中绘制成Path。与此类似,Geometry中最强大的还是PathGeometry。上面图片中的五角形就是将Path数据转换成PathGeometry的。XAML代码如下:
<Border Width="180"
Height="180"
Margin="3"
Background="Aquamarine">
<Border Background="LightPink" Clip="M90.000003,0.5 L111.12693,68.873594 L179.50001,68.871913 L124.18408,111.12744 L145.31405,179.49999 L90.000003,137.24175 L34.685959,179.49999 L55.815923,111.12744 L0.50000013,68.871913 L68.87308,68.873594 z" />
</Border>
话说,只看XAML代码真看不出这是什么鬼东西。
下载链接
博客园:HoleWithClip
OpacityMask与Clip区别
可以看出,通过OpacityMask和Clip都能实现打洞效果。但是通过OpactiyMask实现的效果在空洞中间会引发相应的事件,而Clip则不会,原因是在于UIElement中作命中测试考虑到了Clip的存在。应根据实际需求选择不同的实现方式。
利用Clip制作打洞效果的更多相关文章
- 利用OpacityMask制作打洞效果
起因 项目上存在一个连线功能,在设计的原型中,在连线中间文字上下各有15像素的空白.接手的同事觉得没思路,问我能不能在不影响连线后面的背景情况下解决该问题.我就抽了点时间给他写了个Demo.回家后趁热 ...
- 利用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代码:// ...
随机推荐
- 自定义View_2_关于自定义组合View
自定义View(2) Android当中给我们提供了丰富的UI控件,当然也许满足不了我们的需求,我们就必须学会自定义自己的View,我们怎么算是自定义自己的view呢! 我们会根据原来有的View对V ...
- Android应用开发基础之九:内容提供者(ContentProvider)
内容提供者 应用的数据库是不允许其他应用访问的 内容提供者的作用:就是让别的应用访问到你的数据库 自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查数据库的代 ...
- XML的约束(dtd)
DTD(Document Type Definition),文档类型定义,DTD文件应使用UTF-8或Unicode 1.XML中有多少个元素,就在dtd文件中写几个 <!ELEMENT&g ...
- elasticsearch分词插件的安装
IK简介 IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包.从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本.最初,它是以开源项目Luen ...
- 安装SQL Server Management Studio Express错误码是29506
解决方法:1:新建一个记事本,输入msiexec /i path\SQLServer2005_SSMSEE.msi 然后另存为.cmd格式.2:右单击刚刚创建的那个.CMD文件,选择“以管理员身份运行 ...
- android studio问题rendering problems no render target selected
activity_main.xml选择Design显示rendering problems no render target selected 在stackOverflow上找到了答案: You ne ...
- iOS 你将会遇到的
1.解释ARC原理,ARC引入之后,iOS增加了几个修饰符,分别是什么?并解释何时应该使用? 2.给你一个可变数组aMutableArray,请写出你认为较好的算法代码. 3.UITableView是 ...
- 既生瑜何生亮?ASP.NET MVC VS ASP.NET Web API
Asp.net MVC 与 Asp.net Web API 区别 在我们开发一些web应用时,我们一样可以在MVC Framework 中使用JsonResult 来返回JSON数据,同样也可以处理一 ...
- tomcat部署
因为之前一直用的JBoss服务器,今天测试了一下想换成tomcat,然后就考了一个现成的tomcat,然后将jboss下的项目复制了一个到tomcat下,然后改了一下文件名,结果启动时报错 java. ...
- Linux磁盘、目录、文件操作命令
0x01. Linux磁盘分区与目录结构 ① 主分区.拓展分区.逻辑分区:早期主引导扇区MBR用64B存放主分区信息,每个分区用16B,因而上限为4个主分区,后来,因分区需求,引入拓展分区(类主分区) ...