這篇文章將為大家詳細(xì)講解有關(guān)iOS中如何使用一行代碼實(shí)現(xiàn)UIView鏤空效果,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
目前創(chuàng)新互聯(lián)已為近1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計(jì)、伍家崗網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
一、思路
我們的最終目標(biāo)是,封裝出一個(gè)接口,調(diào)用方式類似于 maskView
屬性,可以很方便地對(duì)一個(gè) UIView
做鏤空效果。
注:以下用 originView
指代需要上效果的 view
,用 maskView
指代充當(dāng)遮罩的 view
。
目前看來(lái),可以從兩個(gè)方向入手:
修改遮罩的繪制過(guò)程修改 maskView 本身
方式一是指,在設(shè)置這個(gè)屬性的時(shí)候,對(duì) originView
的視圖進(jìn)行重新繪制,然后在繪制的時(shí)候,減掉 maskView
的區(qū)域。
方式二是指,當(dāng)拿到 maskView
的時(shí)候,先對(duì) maskView
本身先進(jìn)行處理,將遮罩范圍取反。然后再做遮罩效果,由于遮罩的區(qū)域已經(jīng)相反,于是得到的結(jié)果也是相反的,就達(dá)到鏤空的目的。
看上去方式二比較靠譜,而且最后是調(diào)用 UIView
的 setMaskView:
來(lái)實(shí)現(xiàn),還可以保留原來(lái)遮罩的一些特性。比如當(dāng)修改 maskView
的 frame
的時(shí)候, originView
的遮罩位置也會(huì)相應(yīng)改變。
二、實(shí)現(xiàn)
生成相反的遮罩圖可以分為三步。假設(shè)一開(kāi)始拿到的 maskView
是下面這樣,讓我們來(lái)看下,轉(zhuǎn)換過(guò)程中遮罩圖每一步的變化。
注:為了更直觀的效果,圖片中透明的部分用灰白相間格子來(lái)表示(以下相同)。
1、將 maskView
轉(zhuǎn)化為 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
對(duì)應(yīng)的 image
圖像。此時(shí)遮罩圖的大小會(huì)被同步為 originView
的大小。
2、將
UIImage
轉(zhuǎn)換為只有 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);
這時(shí)候的 alphaOnlyContext
對(duì)應(yīng)的圖像是下面這樣,只保留了 alpha
通道。
3、將
CGContextRef
中的 alpha
值進(jìn)行遍歷轉(zhuǎn)換
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];
轉(zhuǎn)換后,獲得的 result
圖像是:
于是,我們就可以用 result
愉快地進(jìn)行 mask
了。
三、使用
我們可以將上述的步驟,封裝為一個(gè)方法,用 category
來(lái)實(shí)現(xiàn)。
@interface UIView (MFSubtractMask)- (void)setSubtractMaskView:(UIView *)view;- (UIView *)subtractMaskView;@end
這樣調(diào)用起來(lái)就十分方便了,一行代碼搞定:
view.subtractMaskView = maskView;
四、局限性
1. subtractMaskView
不會(huì)自動(dòng)刷新
我們知道,當(dāng) UIView
的 maskView
的內(nèi)容動(dòng)態(tài)修改時(shí),會(huì)實(shí)時(shí)反映到 UIView
中。但在本項(xiàng)目中, subtractMaskView
屬性會(huì)生成一張全新的圖片來(lái)作為遮罩圖,因?yàn)椴粫?huì)根據(jù) subtractMaskView
的內(nèi)容實(shí)時(shí)來(lái)刷新視圖。如果需要更新,必須手動(dòng)調(diào)用 setSubtractMaskView:
方法來(lái)重新生成遮罩圖。
2. setSubtractMaskView:
不宜被頻繁調(diào)用
setSubtractMaskView:
本質(zhì)上是生成一個(gè)新的遮罩圖的過(guò)程,該過(guò)程涉及圖片像素的遍歷轉(zhuǎn)換,較為耗時(shí),不宜頻繁調(diào)用。
關(guān)于“iOS中如何使用一行代碼實(shí)現(xiàn)UIView鏤空效果”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。