起因

如上篇博文所说,连线原型需要在中间文字上下各留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制作打洞效果的更多相关文章

  1. 利用OpacityMask制作打洞效果

    起因 项目上存在一个连线功能,在设计的原型中,在连线中间文字上下各有15像素的空白.接手的同事觉得没思路,问我能不能在不影响连线后面的背景情况下解决该问题.我就抽了点时间给他写了个Demo.回家后趁热 ...

  2. 利用css3制作毛玻璃的效果

    忙里偷闲,最近又在看许多比较酷炫的效果.现在基于jquery的插件比较多,但是很多插件的兼容性不是太好,所以原生的才是王道.在日常当中,毛玻璃已经不常见了,那是一个很久远年代的东西了.诺,下面就是毛玻 ...

  3. 分享一个利用HTML5制作的海浪效果代码

    在前面简单讲述了一下HTML里的Canvas,这次根据Canvas完成了“海浪效果”(水波上升). (O(∩_∩)O哈哈哈~作者我能看这个动画看一下午) 上升水波.gif 动画分析构成:贝塞尔曲线画布 ...

  4. flash8中利用遮罩制作图片切换效果

    http://www.56.com/w73/play_album-aid-8642763_vid-NDY5ODU2Mzg.html

  5. 利用TabHost制作QQ客户端标签栏效果(低版本QQ)

    学习一定要从基础学起,只有有一个好的基础,我们才会变得更加的perfect 下面小编将利用TabHost制作QQ客户端标签栏效果(这个版本的QQ是在前几年发布的)…. 首先我们看一下效果: 看到这个界 ...

  6. 纯代码利用CSS3 圆角边框和盒子阴影 制作 iphone 手机效果

    原文:纯代码利用CSS3 圆角边框和盒子阴影 制作 iphone 手机效果 大家好,我是小强老师. 今天我们看下CSS3最为简单的两个属性. css3给我们带来了很多视觉的感受和变化,以前的图片做的事 ...

  7. 利用CSS3制作淡入淡出动画效果

    CSS3新增动画属性“@-webkit-keyframes”,从字面就可以看出其含义——关键帧,这与Flash中的含义一致. 利用CSS3制作动画效果其原理与Flash一样,我们需要定义关键帧处的状态 ...

  8. 利用FluidMoveBehavior制作出手机通讯录平滑的效果

    最近学习Blend,原来Blend制作动画等效果非常棒.下面演示一下FluidMoveBehavior应用,利用Blend中行为中的FluidMoveBehavior制作出手机通讯录平滑的效果 1.在 ...

  9. WPF设置VistualBrush的Visual属性制作图片放大镜效果

    原文:WPF设置VistualBrush的Visual属性制作图片放大镜效果 效果图片:原理:设置VistualBrush的Visual属性,利用它的Viewbox属性进行缩放. XAML代码:// ...

随机推荐

  1. [Windows Phone] APP上架,遇到错误2001的解决方案。(Error:2001)

    [Windows Phone] APP上架,遇到错误2001的解决方案.(Error:2001) 问题情景 最近在开始玩Windows Phone的开发,开发的过程中虽然有点小挫折,但是参考网络许多前 ...

  2. Ansible用于网络设备管理 part 3 使用NAPALM成品库

    闲话 经过了这俩月的闲暇时间的瞎逛和瞎琢磨,我发现NAPALM是一条路,NAPALM是由帅哥David Barroso和美女Elisa Jasinska创建的一个项目,都是颜值高的技术牛人啊,真是不给 ...

  3. js验证真实姓名与身份证号,手机号

    最近的项目中用的需要调用实名认证的接口,实名认证接口价格相比短信而言高了不是几分钱,所以说调用实名认证的条件就要严格把关,因此用到js验证真实姓名与js验证身份证号. 进入正题 1.js验证真实姓名 ...

  4. SAP RFC通信模式

    在网络技术中,数据通信可以大致划分为两种基本模式:同步通信和异步通信. 其本义是:异步通信时,通信双方时钟允许存在一定误差:同步通信时,双方时钟的允许误差较小.在SAP的系统间的通信过程中,也借用术语 ...

  5. Android studio打包APK混淆配置

    要在打包APK时加入混淆需要在Module中的buid.gradle中加入如下信息 buildTypes { release { minifyEnabled true shrinkResources ...

  6. Emacs常用命令汇总

    注意:以下命令中标注的按键,大写的C代表Control,在键盘上通常是Ctrl键,而M代表Meta,在键盘上通常是Alt键,S则代表Shift,在键盘上通常是Shift键,也就是 C Control ...

  7. 【读书笔记】iOS-复制的种类

    一,你可以使用不同的方法复制对象.大多数对象都引用(即指向)其它对象. 二,浅层复制,不复制引用对象,新复制的对象只指向现有的引用对象.NSArray类的copy方法是浅层复制.当复制一个NSArra ...

  8. NSArray数字和排序

    1.数字 int main(int argc, const char * argv[]) { @autoreleasepool { //添加空白 [NSNull null] // NSArray *a ...

  9. LeetCode 1 Two Sum(二分法)

    题目来源:https://leetcode.com/problems/two-sum/ Given an array of integers, find two numbers such that t ...

  10. 【转载】改善数据质量从数据剖析(Data Profiling)开始

    市场研究公司Forrester副总裁Erin Kinikin曾经把低劣的数据质量做了一个形象的比喻“用更好的方法访问劣质的数据,结果类似于把已经腐烂了的桃子用更快的卡车,走更好的路线运输到达市场时,桃 ...