博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用OpacityMask制作打洞效果
阅读量:5275 次
发布时间:2019-06-14

本文共 7461 字,大约阅读时间需要 24 分钟。

原文:

起因

项目上存在一个连线功能,在设计的原型中,在连线中间文字上下各有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;    ///     /// 矩形空洞的转换器    ///     public class RectangleHoleConverter : IMultiValueConverter    {        ///         /// 转换成矩形空洞        ///         ///         /// 转换值列表,第一个表示起始宽度,第二个表示起始高度,        /// 第三个表示总宽度,第四个表示总高度        /// 第五个表示宿主宽度,第六个表示宿主宽度        ///         ///         ///         ///         /// 
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    {        ///         /// 枚举器中是否存在null条目        ///         /// 
元素类型
/// 元素枚举 ///
存在null条目返回true,否则返回false
public static bool HaveNullItem
(this IEnumerable
enumerable) { return enumerable.Any(item => item == null); } ///
/// 枚举器中是否全为指定类型的实例 /// ///
元素类型
///
元素枚举 ///
全为指定类型的实例返回true,否则返回false
public static bool IsAllInstanceOfType
(this IEnumerable
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;    ///     /// 椭圆形空洞的转换器    ///     public class EllipseHoleConverter : IMultiValueConverter    {        ///         /// 转换成矩形空洞        ///         ///         /// 转换值列表,第一个表示起始宽度,第二个表示起始高度,        /// 第三个表示总宽度,第四个表示总高度        /// 第五个表示宿主宽度,第六个表示宿主宽度        ///         ///         ///         ///         /// 
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代码如下:

容易看出,PNG图片中透明的就真的透明了(直接看到外层Border上级的背景BurlyWood了),不透明的地方就使用了当前Border设置的背景色LightPink。

更多

还可使用线性渐变(LinearGradientBrush)、径向渐变(RadialGradientBrush)实现更多有趣的效果,下图是MSDN中的一个例子

纯色画刷(SolidColorBrush)基本用不到,要么透明,要么不透明,还不如直接设置Opacity。

下载链接

博客园:

posted on
2019-01-04 00:59 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/10217755.html

你可能感兴趣的文章
161017、SQL必备知识点
查看>>
kill新号专题
查看>>
MVC学习系列——Model验证扩展
查看>>
mysqladmin 修改和 初始化密码
查看>>
字符串
查看>>
vue2.x directive - 限制input只能输入正整数
查看>>
实现MyLinkedList类深入理解LinkedList
查看>>
自定义返回模型
查看>>
C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 客户端多网络支持
查看>>
HDU 4122
查看>>
Suite3.4.7和Keil u3自带fx2.h、fx2regs.h文件的异同
查看>>
打飞机游戏【来源于Crossin的编程教室 http://chuansong.me/account/crossincode 】
查看>>
[LeetCode] Merge Intervals
查看>>
【翻译自mos文章】当点击完 finishbutton后,dbca 或者dbua hang住
查看>>
Linux编程简介——gcc
查看>>
2019年春季学期第四周作业
查看>>
MVC4.0 利用IActionFilter实现简单的后台操作日志功能
查看>>
rotate the clock
查看>>
bugku 变量
查看>>
Python 环境傻瓜式搭建 :Anaconda概述
查看>>