iOS中一行代码实现 UIView 镂空效果

这是一种实现 UIView 镂空效果的方案,可以快速实现任意形状的镂空、文字的镂空、带镂空的毛玻璃效果等。本质上是 UIViewmaskView 效果。

前言

首先来复习一下遮罩效果的实现。如果我们有一张图片,又恰好有一个圆,当我们把圆设置为图片的遮罩时,会得到这样的结果。

代码实现看上去像是这样:

view.maskView = maskView;

那么问题来了,如果我们希望得到下面的结果,该怎么做呢?这看起来像是图层的相减,即原来的图层减去遮罩的部分。

可惜苹果爸爸不够贴心,没有提供方便的接口调用。让我们来看看可以怎么实现。

一、思路

我们的最终目标是,封装出一个接口,调用方式类似于 maskView 属性,可以很方便地对一个 UIView 做镂空效果。

注:以下用 originView 指代需要上效果的 view ,用 maskView 指代充当遮罩的 view

目前看来,可以从两个方向入手:

  1. 修改遮罩的绘制过程
  2. 修改 maskView 本身

方式一是指,在设置这个属性的时候,对 originView 的视图进行重新绘制,然后在绘制的时候,减掉 maskView 的区域。

方式二是指,当拿到 maskView 的时候,先对 maskView 本身先进行处理,将遮罩范围取反。然后再做遮罩效果,由于遮罩的区域已经相反,于是得到的结果也是相反的,就达到镂空的目的。

看上去方式二比较靠谱,而且最后是调用 UIViewsetMaskView: 来实现,还可以保留原来遮罩的一些特性。比如当修改 maskViewframe 的时候, originView 的遮罩位置也会相应改变。

二、实现

生成相反的遮罩图可以分为三步。假设一开始拿到的 maskView 是下面这样,让我们来看下,转换过程中遮罩图每一步的变化。

注:为了更直观的效果,图片中透明的部分用灰白相间格子来表示(以下相同)。

1、将 maskView 转化为 UIImage

UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
CGContextTranslateCTM(UIGraphicsGetCurrentContext(),
           view.frame.origin.x,
           view.frame.origin.y);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

这一步拿到了 maskView 对应的 image 图像。此时遮罩图的大小会被同步为 originView 的大小。

2、将

UIImage 转换为只有 alpha 通道的 CGContextRef

CGImageRef originalMaskImage = [image CGImage];
float width = CGImageGetWidth(originalMaskImage);
float height = CGImageGetHeight(originalMaskImage);

int strideLength = ROUND_UP(width * 1, 4);
unsigned char * alphaData = calloc(strideLength * height, sizeof(unsigned char));
CGContextRef alphaOnlyContext = CGBitmapContextCreate(alphaData,
                           width,
                           height,
                           8,
                           strideLength,
                           NULL,
                           kCGImageAlphaOnly);

CGContextDrawImage(alphaOnlyContext, CGRectMake(0, 0, width, height), originalMaskImage);

这时候的 alphaOnlyContext 对应的图像是下面这样,只保留了 alpha 通道。

3、将

CGContextRef 中的 alpha 值进行遍历转换

for (int y = 0; y < height; y++) {
  for (int x = 0; x < width; x++) {
    unsigned char val = alphaData[y*strideLength + x];
    val = 255 - val;
    alphaData[y*strideLength + x] = val;
  }
}

CGImageRef alphaMaskImage = CGBitmapContextCreateImage(alphaOnlyContext);
UIImage *result = [UIImage imageWithCGImage:alphaMaskImage];

转换后,获得的 result 图像是:

于是,我们就可以用 result 愉快地进行 mask 了。

三、使用

我们可以将上述的步骤,封装为一个方法,用 category 来实现。

@interface UIView (MFSubtractMask)
- (void)setSubtractMaskView:(UIView *)view;
- (UIView *)subtractMaskView;
@end

这样调用起来就十分方便了,一行代码搞定:

view.subtractMaskView = maskView;

四、局限性

1. subtractMaskView 不会自动刷新

我们知道,当 UIViewmaskView 的内容动态修改时,会实时反映到 UIView 中。但在本项目中, subtractMaskView 属性会生成一张全新的图片来作为遮罩图,因为不会根据 subtractMaskView 的内容实时来刷新视图。如果需要更新,必须手动调用 setSubtractMaskView: 方法来重新生成遮罩图。

2. setSubtractMaskView: 不宜被频繁调用

setSubtractMaskView: 本质上是生成一个新的遮罩图的过程,该过程涉及图片像素的遍历转换,较为耗时,不宜频繁调用。

综上所述,这种方案适合只生成一次遮罩图的场景。

五、源码

请到 GitHub上查看完整代码。

总结

以上所述是小编给大家介绍的iOS中一行代码实现 UIView 镂空效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • iOS App开发中UIViewController类的使用教程

    一.引言 作为MVC设计模式中的C,Controller一直扮演着项目开发中最重要的角色,它是视图和数据的桥梁,通过它的管理,将数据有条有理的展示在我们的View层上.iOS中的UIViewController是UIKit框架中最基本的一个类.从第一个UI视图到复杂完整项目,都离不开UIViewController作为基础.基于UIViewController的封装和扩展,也能够出色的完成各种复杂界面逻辑.这里旨在讨论UIViewController的生命周期和属性方法,在最基础的东西上,往往会

  • iOS为UIView设置阴影效果

    UIView的阴影设置主要通过UIView的layer的相关属性来设置 阴影的颜色 imgView.layer.shadowColor = [UIColor blackColor].CGColor; 阴影的透明度 imgView.layer.shadowOpacity = 0.8f; 阴影的圆角 imgView.layer.shadowRadius = 4.f; 阴影偏移量 imgView.layer.shadowOffset = CGSizeMake(4,4); imgView.layer.s

  • 详解iOS中UIView的layoutSubviews子视图布局方法使用

    概念 在UIView里面有一个方法layoutSubviews: 复制代码 代码如下: - (void)layoutSubviews;    // override point. called by layoutIfNeeded automatically. As of iOS 6.0, when constraints-based layout is used the base implementation applies the constraints-based layout, other

  • IOS代码笔记UIView的placeholder的效果

    本文实例为大家分享了IOS占位符效果,供大家参考,具体内容如下 一.效果图 二.工程图 三.代码 RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController : UIViewController <UITextViewDelegate> { UITextView *psTextView; UILabel *pslabel; } @end RootViewController.m #import

  • 详解iOS App开发中UIViewController的loadView方法使用

    当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewController就会自动调用loadView这个方法.这个方法就会加载或者创建一个view对象,赋值给view属性. loadView默认做的事情是:如果此ViewController存在一个对应的nib文件,那么就加载这个nib.否则,就创建一个UIView对象. 如果你用Interface Builder来创建界面,那么不应该重载这个方法. 控制器的loadView方法以及view属性

  • iOS中一行代码实现 UIView 镂空效果

    这是一种实现 UIView 镂空效果的方案,可以快速实现任意形状的镂空.文字的镂空.带镂空的毛玻璃效果等.本质上是 UIView 的 maskView 效果. 前言 首先来复习一下遮罩效果的实现.如果我们有一张图片,又恰好有一个圆,当我们把圆设置为图片的遮罩时,会得到这样的结果. 代码实现看上去像是这样: view.maskView = maskView; 那么问题来了,如果我们希望得到下面的结果,该怎么做呢?这看起来像是图层的相减,即原来的图层减去遮罩的部分. 可惜苹果爸爸不够贴心,没有提供方

  • 基于jquery的一行代码轻松实现拖动效果

    实现拖动效果. 复制代码 代码如下: $(document).ready( function() { $("#divPanel").easydrag(); } ); Html 代码 复制代码 代码如下: <div id="divPanel" style="width:300px;height:300px;background:white;border:1px solid #000000;position:absolute;left:5px;top:5

  • php一行代码获取文件后缀名实例分析

    本文实例讲述了php一行代码获取文件后缀名的方法.分享给大家供大家参考.具体方法分析如下: php中一行代码获取文件后缀名的方法要结合很多的函数了,我们这个有点像asp中的函数了,下面来一起看看吧. 实例: 复制代码 代码如下: $filename  = 'D:/wamp/www/sparkphp/rar'; $rs =  strtolower(trim(substr(strrchr($filename, "."), 1))); 详解: strrchr()函数查找字符串在另一个字符串中

  • iOS 引导页的镂空效果实例

    初衷 最近项目新功能更改较大,产品童鞋要求加入新功能引导,于是一口气花了两天的时间做了一个引导页,当然加上后面的修修补补的时间,就不只两天了,不过这事情其实是一劳永逸的事情,值得做.同时为了能够更好的复用,我把它做成了pod库,项目地址在这里:EAFeatureGuideView. EAFeatureGuideView能做什么 EAFeatureGuideView是UIView的一个扩展,用来做新功能引导提示,达到这样的效果: 局部区域高亮(可以设置圆角) 有箭头指向高亮区域 可以设置一段介绍文

  • iOS 中根据屏幕宽度自适应分布按钮的实例代码

    下载demo链接:https://github.com/MinLee6/buttonShow.git 屏幕摆放的控件有两种方式,一种根据具体内容变化,一种根据屏幕宽度变化. 下面我分别将两个方式,用代码的方式呈现: 1:根据具体内容变化 // // StyleOneViewController.m // buttonShow // // Created by limin on 15/06/15. // Copyright © 2015年 信诺汇通信息科技(北京)有限公司. All rights

  • iOS中实现图片自适应拉伸效果的方法

    前言 在Android中实现图片的拉伸特别特别简单,甚至不用写一行代码,直接使用.9图片进行划线即可.但是iOS就没这么简单了,比如对于下面的一张图片(原始尺寸:200*103): 我们不做任何处理,直接将它用作按钮的背景图片: // // ViewController.m // ChatBgTest // // Created by 李峰峰 on 2017/1/23. // Copyright © 2017年 李峰峰. All rights reserved. // #import "View

  • iOS开发中的ViewController转场切换效果实现简介

    在iOS7之前,View Controller的切换主要有4种: Push/Pop,NavigationViewController Present and dismis Modal UITabBarController addChildViewController(一般用于自定义的继承于 UIViewController 的容器子类) iOS5,调用- (void)transitionFromViewController:(UIViewController *)fromViewControll

  • iOS中自定义弹出pickerView效果(DEMO)

    UIPickerView平常用的地方好像也不是很多,顶多就是一些需要选择的地方,这次项目需要这一个功能,我就单独写了一个简单的demo,效果图如下: 新增主页面弹出view,在主页面添加的代码 有个小问题就是第四个直接添加在主页弹出来的view好像被导航栏给覆盖了,我还没去研究,就着急的先吧功能写了.大家谅解下 最初版本 话说我终于弄了gif了,再也不要去截图每张图都发一遍了!! 这个demo呢,等于是可以拿来直接用的第三方了吧,只需要传数据就可以了,弹出的三个框显示的数据也不一样,我的封装能力

  • IOS中各种手势操作实例代码

    先看下效果 手势相关的介绍 IOS中手势操作一般是 UIGestureRecognizer 类的几个手势子类去实现,一般我们用到的手势就这么5种: 1.点击  UITapGestureRecognizer 2.平移  UIPanGestureRecognizer 3.缩放  UIPinchGestureRecognizer 4.旋转  UIRotationGestureRecognizer 5.轻扫  UISwipeGestureRecognizer 我们上面这个实例中就用到了上面这5种手势,不

  • iOS中实现简单易懂秒杀倒计时/倒计时代码

    示例代码简单易懂: #import <uikit uikit.h=""> @interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *dayLabel; @property (weak, nonatomic) IBOutlet UILabel *hourLabel; @property (weak, nonatomic) IBOutlet UILabel

随机推荐