【iOS】氣泡樣式視圖

前言

在一個UITextField 或者 UITextView中長按,屏幕就會出現(xiàn)一個輔助編輯的工具條馒吴。這個工具條的輪廓是一個帶三角形箭頭的圓角矩形偎漫,看起來就像是一個氣泡樣式的提示框唁影,這是一種非常常見的形狀效果。
UIKit里的UIPopoverPresentationController可以讓一個Controller以這種形式展示谜慌。但是如果要對View進行操作,似乎就沒有比較直接的方法莺奔,有一種解決方法是對其layermask屬性進行設(shè)置欣范。

方法一: 用圖片mask

要做出這種效果,有一種速成方法令哟。首先做一張下面這樣的png圖片恼琼,然后把這張圖片設(shè)置為一個CALayer對象的contents,再用這個CALayermask目標Viewlayer屏富。

代碼示例:

UIImage *img = [UIImage imageNamed:@"Bubble.png"];
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = myView.bounds;
maskLayer.contents = (__bridge id _Nullable)(img.CGImage);
myView.layer.mask = maskLayer;     

myView.layer.backgroundColor = [UIColor purpleColor].CGColor;

很顯然晴竞,這種實現(xiàn)方法可定制性不高,如果需要把三角形箭頭的位置居中,或者把它放在矩形框的左方狠半,又或者需要修改一下圓角的弧度......面對這些要求噩死,可能需要做更多的png圖片颤难。

方法二: 用“筆”畫出來

仔細看一下這個形狀,它無非就是幾條直線加上一些圓角已维,事實上完全可以用“筆”把它畫出來乐严。

前期準備

在開始繪制圖形之前,我們需要先定位一些關(guān)鍵的“點”衣摩。如下圖所示昂验,灰色虛線外框是需要mask的目標視圖的大小,綠色區(qū)域是最終要繪制的圖形艾扮,而紅色點的坐標在繪制過程中需要使用既琴。

假定我們按照順時針方向繪制這個圖形,并且先畫“箭頭”泡嘴,再圓角矩形框甫恩。那么我們先把這些紅點按照順時針方向編號,并且暫時把它們放進數(shù)組里points中酌予。

除此之外磺箕,我們還要理解void CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius)這個函數(shù)。前四個參數(shù)用來指定兩個跟繪制有關(guān)的坐標點抛虫,最后一個參數(shù)用來指定圓角的半徑(如果這個參數(shù)為0松靡,則不會有圓角效果)。除了這五個參數(shù)以外建椰,這個函數(shù)還會受一個坐標點影響雕欺,就是繪畫的那支“筆”當前所在的坐標。
舉個例子棉姐,先看下面這張圖:

pointtApointB指定了函數(shù)的前四個參數(shù)屠列,radius就是最后一個參數(shù),“畫筆”當前所在的坐標點就是Current point伞矩,那么上述函數(shù)根據(jù)這些參數(shù)繪制出來的曲線就是黑色的實線笛洛。

動筆

有了上面這些準備之后,終于可以動筆了乃坤。

// 獲取上下文
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    
// 因為第一步是要畫箭頭處的那個“0”的地方
// 所以把“筆”放在“0”在順時針方向順序的上一個點: “6”
CGPoint currentPoint = [[points objectAtIndex:6] CGPointValue];
CGContextMoveToPoint(ctx, currentPoint.x, currentPoint.y);
    
CGPoint pointA, pointB;
CGFloat radius;
    
int i = 0;
while(i<7) {
    // 整個過程需要7次循環(huán)
              
    // 箭頭處(0,1,2三個點)是三個尖角苛让,矩形框是四個圓角
    radius = i < 3 ?  0 : 10;
    // radius = i < 3 ? 4 : 10; // 全畫成圓角
    pointA = [[points objectAtIndex:i] CGPointValue];
    // 畫矩形框最后一個圓角的時候,pointB就是points[0]
    pointB = [[points objectAtIndex:(i+1)%7] CGPointValue];

    CGContextAddArcToPoint(ctx, pointA.x, pointA.y, pointB.x, pointB.y, radius);
    i = i + 1;
}

// 獲取path
CGContextClosePath(ctx);
CGPathRef path = CGContextCopyPath(ctx);
UIGraphicsEndImageContext();

// 生成layer    
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = path;

// 設(shè)置目標view的layer的mask屬性    
myView.layer.mask = maskLayer;

代碼封裝

由于我覺得平時可能經(jīng)常會用到這種形狀效果侥袜,所以我把它封裝起來了蝌诡。這樣每次需要做這種效果的時候,只需根據(jù)Viewsize去調(diào)用接口就可以了枫吧。

示例:

    BubbleLayer *bbLayer = [[BubbleLayer alloc]initWithSize:myView.bounds.size];
    // 提供的一些自定義設(shè)置
    // bubbleLayer.arrowDirection = ArrowDirectionTop;
    // bubbleLayer.arrowHeight = 12;
    // bubbleLayer.arrowWidth = 18;
    // bubbleLayer.arrowPosition = 0.3;
    [myView.layer setMask:[bbLayer layer]];

封裝的工作就是提供一些個性化的參數(shù)設(shè)置浦旱,比如“箭頭”的高度、寬度九杂、方向以及相對位置颁湖,還有矩形框的圓角半徑這些宣蠕。進一步的,還有根據(jù)這些個性化的參數(shù)和Viewsize甥捺,去計算上面說到的7個關(guān)鍵點抢蚀。這些工作都比較簡單,所以我就不再贅述了镰禾,完整代碼(包括Swift版)我放在了Github倉庫皿曲。

倉庫鏈接: https://github.com/iHandle/BubbleLayer

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吴侦,隨后出現(xiàn)的幾起案子屋休,更是在濱河造成了極大的恐慌,老刑警劉巖备韧,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劫樟,死亡現(xiàn)場離奇詭異,居然都是意外死亡织堂,警方通過查閱死者的電腦和手機叠艳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來易阳,“玉大人附较,你說我怎么就攤上這事∶隼樱” “怎么了翅睛?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長黑竞。 經(jīng)常有香客問我,道長疏旨,這世上最難降的妖魔是什么很魂? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮檐涝,結(jié)果婚禮上遏匆,老公的妹妹穿的比我還像新娘。我一直安慰自己谁榜,他們只是感情好幅聘,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窃植,像睡著了一般帝蒿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巷怜,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天葛超,我揣著相機與錄音暴氏,去河邊找鬼。 笑死绣张,一個胖子當著我的面吹牛答渔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播侥涵,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼沼撕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芜飘?” 一聲冷哼從身側(cè)響起端朵,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎燃箭,沒想到半個月后冲呢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡敬拓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了累榜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壹罚。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡猖凛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虱岂,到底是詐尸還是另有隱情菠红,我是刑警寧澤试溯,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站猎塞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荠耽。R本人自食惡果不足惜比藻,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慢叨。 院中可真熱鬧务蝠,春花似錦、人聲如沸馏段。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砍濒。三九已至爸邢,卻和暖如春庶香,著一層夾襖步出監(jiān)牢的瞬間赶掖,已是汗流浹背七扰。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工膳灶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人轧钓。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓毕箍,卻偏偏與公主長得像弛房,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子而柑,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容