前言
微信在最新版本6.6.7,新加了一個文章懸浮球功能。當(dāng)你正在閱讀文章的時候,突然有好友發(fā)來了緊急消息,你需要立即回復(fù)。又或者你剛好路過小吃店,需要臨時打開微信支付,等等臨時中斷閱讀的情況。以前只有退出文章詳情頁面,處理完事情之后,再挨著挨著找到原來的文章。對于我們這種重度微信使用者來說,每次遭遇這種情況,真的很蛋疼。所以,當(dāng)這個功能推出的事情,立馬更新了最新版本,這個功能感覺就像遇到了知心人一樣,用起來十分順手。可以通過下面的動圖感受一下
其實懸浮球的概念早就有了。比如360助手的流量監(jiān)控球,iphone自帶的assitivetouch(就是那個可愛的小白球)等等。
倉庫地址
github地址 喜歡就點顆:heart:
核心技術(shù)點
體驗過后,讓人手癢癢,情不自禁得想要模仿一把。如果你的app可以集成該功能,我覺得可以讓你的app逼格瞬間提升一個level。好了,下面讓我們來一一解剖,微信文章懸浮球的核心技術(shù)點:
1.懸浮球的出現(xiàn)
當(dāng)我們通過屏幕邊緣手勢pop視圖的時候,右下角會有一個圓角提示圖,跟著手勢進(jìn)度移動。
如何獲取到uiscreenedgepangesturerecognizer的進(jìn)度呢?
因為系統(tǒng)自帶的interactivepopgesturerecognizer是被封裝起來的,它的action我們無法掛鉤拿到里面的手勢進(jìn)度。所以,需要另辟蹊徑了。
首先,讓uinavigationcontroller的delegate等于自己,然后讓多個手勢可以同時響應(yīng)。
1
2
3
4
5
|
self.interactivepopgesturerecognizer?.delegate = self func gesturerecognizer(_ gesturerecognizer: uigesturerecognizer, shouldrecognizesimultaneouslywith othergesturerecognizer: uigesturerecognizer) -> bool { return true } |
然后自己添加一個uiscreenedgepangesturerecognizer到uinavigationcontroller上面,用于獲取pop手勢的進(jìn)度。
1
2
3
|
let gesture = uiscreenedgepangesturerecognizer(target: self, action: #selector(handlenavigationtransition(gesture:))) gesture.edges = .left self.view.addgesturerecognizer(gesture) |
這樣子,有兩個uiscreenedgepangesturerecognizer可以同時響應(yīng),系統(tǒng)自帶的依然保持原有邏輯不動,我們新增的用于獲取pop手勢進(jìn)度,兩者井水不犯河水,其樂融融。
2.懸浮球全局置頂
既然懸浮球可以在懸浮在任何一個頁面,必然是放在一個新的uiwindow上面。比如系統(tǒng)的鍵盤彈出的時候,就是一個uiremotekeyboardwindow在承載。
然后這個window的生命周期不依賴某一個頁面,所以用單例實現(xiàn)比較好。這塊代碼比較分散,直接看源碼就可以了解
3.事件響應(yīng)
懸浮uiwindow的事件傳遞
只要事件位置沒有在圓球和右下角上,就不響應(yīng)
1
2
3
4
5
6
7
8
9
10
11
|
override func point(inside point: cgpoint, with event: uievent?) -> bool { let roundentryviewpoint = self.convert(point, to: roundentryview) if roundentryview.point(inside: roundentryviewpoint, with: event) == true { return true } let collectviewpoint = self.convert(point, to: collectview) if collectview.point(inside: collectviewpoint, with: event) == true { return true } return false } |
右下角四分之一圓,事件響應(yīng)
可以看到微信,只有當(dāng)手指移動進(jìn)右下角圓內(nèi),才能進(jìn)行懸浮。而不是按著視圖的frame來響應(yīng)。
首先,通過uibezierpath畫一個四分之一圓,然后用cgpath的contains(point)
方法判斷。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
func updatebglayerpath(issmall: bool ) { var ratio:cgfloat = 1 if !issmall { ratio = 1.3 } let path = uibezierpath() path.move(to: cgpoint(x: viewsize.width, y: (1 - ratio)*viewsize.height)) path.addline(to: cgpoint(x: viewsize.width, y: viewsize.height)) path.addline(to: cgpoint(x: (1 - ratio)*viewsize.width, y: viewsize.height)) path.addarc(withcenter: cgpoint(x: viewsize.width, y: viewsize.height), radius: viewsize.width*ratio, startangle: cgfloat( double .pi), endangle: cgfloat( double .pi*3/2), clockwise: true ) path.close() bglayer.path = path.cgpath } override func point(inside point: cgpoint, with event: uievent?) -> bool { return bglayer.path!.contains(point) } |
4.自定義轉(zhuǎn)場動畫
可以看到點擊懸浮球打開的文章,是通過一個自定義轉(zhuǎn)場動畫實現(xiàn)的,從懸浮球的位置開始展開。
有許多文章都有講解如何自定義轉(zhuǎn)場動畫,但是我推薦你看這篇文章 幾句代碼快速集成自定義轉(zhuǎn)場效果+ 全手勢驅(qū)動
實現(xiàn)效果
總結(jié)
微信的懸浮球,用到的技術(shù)點相對比較多,代碼也比較分 散,如果你的app要集成該功能,需要認(rèn)真封裝代碼。
相對于如何實現(xiàn),我認(rèn)為如何設(shè)計好一個需求更重要。我在模仿的過程中,發(fā)現(xiàn)其中有許多細(xì)節(jié)的邏輯,彼此環(huán)環(huán)相扣,最終就呈現(xiàn)出了你正在使用的懸浮球功能。
都說程序員和產(chǎn)品經(jīng)理是相愛相殺,在這里我要為該功能的產(chǎn)品經(jīng)理點個贊
倉庫地址
如果代碼中有任何問題,否則你有任何疑問,都可以反饋給我,我將第一時間處理。
github地址 喜歡就點顆:heart:
總結(jié)
以上所述是小編給大家介紹的ios高仿微信文章懸浮球功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對服務(wù)器之家網(wǎng)站的支持!
原文鏈接:http://www.cocoachina.com/ios/20180816/24588.html