[iOS 10 day by day] Day 6:自定義的通知界面

續(xù)上篇爬立,在簡(jiǎn)單鬧鐘的例子上,在通知界面上顯示圖片動(dòng)畫(huà)万哪,并用通知關(guān)聯(lián)的按鈕更新通知界面侠驯。介紹 iOS 10 通知 API 的擴(kuò)展:自定義通知顯示界面。

《iOS 10 day by day》是 shinobicontrols 公司編寫(xiě)的系列博客奕巍,介紹開(kāi)發(fā)者需要了解的 iOS 10 新特性吟策,每周更新。本系列翻譯(文集地址)已取得官方授權(quán)的止。目錄點(diǎn)此檩坚。倉(cāng)薯翻譯,歡迎指正:)

Shinobicontrols 為 iOS 和 Android 開(kāi)發(fā)者提供高性能诅福、響應(yīng)式的 UI 控件 SDK匾委,尤其是圖表方面的控件。 官網(wǎng) : shinobicontrols.com twitter : @shinobicontrols

我們?cè)?Day 5 中介紹了新的 UserNotifications 框架氓润。新框架可以統(tǒng)一處理本地通知和遠(yuǎn)程推送赂乐,同時(shí)增加了一些新 API 來(lái)控制等待中和已發(fā)出的通知。

以上這些都很棒咖气,不過(guò)蘋(píng)果還在通知方面更進(jìn)一步挨措,讓開(kāi)發(fā)者能添加一個(gè)自定義的通知界面挖滤,用戶(hù)收到通知之后可以選擇查看這個(gè)自定義界面。要實(shí)現(xiàn)這個(gè)功能运嗜,需要添加一個(gè)單獨(dú)的 UserNotificationsUI 框架壶辜。這個(gè)框架的 API 特別簡(jiǎn)單,只含有一個(gè)公共的 protocol:UNNotificationContentExtension
担租。

工程

我們的樣例工程是在上一篇文章的鬧鐘 app 基礎(chǔ)上砸民,增加了一個(gè)炫酷的自定義通知界面。通過(guò)這個(gè)界面奋救,用戶(hù)可以不用切換到鬧鐘 app 就能直接取消通知岭参。先來(lái)看下效果:

自定義通知界面效果

跟所有 Day by Day 系列文章一樣,工程源碼放在了 Github 上尝艘。

創(chuàng)建 Extension

iOS 10 的許多旗艦功能都是建立在蘋(píng)果的 Extension 架構(gòu)上的演侯。前面的系列文章 Xcode 插件iMessage 插件 都是如此。而自定義通知界面也是用同樣的方法實(shí)現(xiàn)的背亥。

首先秒际,我們要給鬧鐘 app 的工程加一個(gè)新的 target。在下面這個(gè)選擇 target 模板的界面狡汉,選擇 Notification Content娄徊。然后隨便起個(gè)名字,我用的是 NagMeContentExtension盾戴。

選擇 target 模板

你可能會(huì)注意到寄锐,除了默認(rèn)的Info.plist之外,這個(gè) extension 還包含另外兩個(gè)文件:

  • MainInterface.storyboard : 我們把自定義通知界面的 UI 畫(huà)在這里
  • NotificationViewController.swift : 一個(gè) UIViewController 的子類(lèi)尖啡,這就是自定義界面的 ViewController橄仆,我們通過(guò)這個(gè)類(lèi)來(lái)管理自定義的界面。

把 Extension 與通知 category 關(guān)聯(lián)起來(lái)

現(xiàn)在工程設(shè)置好了衅斩,我們需要讓系統(tǒng)知道盆顾,是哪個(gè)通知要展示這個(gè)界面。不知道你記不記得矛渴,上一篇文章講過(guò)椎扬,一個(gè) category 就是一個(gè)很簡(jiǎn)單的對(duì)象(參考 UNNotificationCategory),里面定義了你的 app 支持哪些類(lèi)型的通知具温,以及每種通知關(guān)聯(lián)了什么操作——就是用戶(hù)把通知展開(kāi)的時(shí)候蚕涤,通知下面出現(xiàn)的那些操作按鈕。

具體實(shí)現(xiàn)這一步铣猩,需要打開(kāi) extension 的 Info.plist揖铜,展開(kāi) NSExtensionAttributes Dictionary,把下面 UNNotificationExtensionCategory 這個(gè)鍵對(duì)應(yīng)的值改為通知 category 的名字("reminder")达皿。注意天吓,這個(gè)值既可以填一個(gè) string 贿肩,也可以填一個(gè) string 數(shù)組,如果想讓多個(gè)通知 category 共用一個(gè) extension 界面就可以填 string 數(shù)組。

Info.plist

現(xiàn)在把工程 Build、Run 一下踏幻,我們可以看到一個(gè)比默認(rèn)的通知彈框更有意思一點(diǎn)的界面察署。

extension 的默認(rèn)界面

管用了屎暇!現(xiàn)在用的是 extension 默認(rèn)的 MainInterface.storyboard 界面,然后是 NotificationViewController 里的模板代碼在更新界面上的 label。不過(guò)這個(gè)界面還是有幾點(diǎn)需要改進(jìn)的地方。首先茂嗓,通知的內(nèi)容("Walk Dog!!")在 extension 的界面上和 DefaultContent 區(qū)域重復(fù)出現(xiàn)了兩次。我們先把這個(gè)重復(fù)的去掉吧科阎!

去掉 DefaultContent

很簡(jiǎn)單述吸,只需在 Info.plist 文件里的 NSExtensionAttributes 下面增加一個(gè) key ,UNNotificationExtensionDefaultContentHidden锣笨,然后值設(shè)為 YES蝌矛,就不會(huì)顯示 DefaultContent 了。

去掉 default content 之后

好错英,下面我們來(lái)寫(xiě)自定義的界面吧朴读。

自定義的通知界面

切換到 MainInterface.storyboard,加上 UI 控件走趋。加一個(gè) label 描述提醒的事項(xiàng),加一個(gè)小喇叭的圖片噪伊。加完之后簿煌,只需拖幾個(gè) IBOutlets 出來(lái),就大功告成啦鉴吹!

收到通知的時(shí)候姨伟,我們要更新 label 上的文本,同時(shí)搖晃小喇叭的圖片——用這種粗暴的方式吸引用戶(hù)的注意力豆励。要實(shí)現(xiàn)這些功能夺荒,需要在 NotificationViewController 里進(jìn)行一些修改。我們的 viewController 實(shí)現(xiàn)了 UNNotificationContentExtension 這個(gè) protocol良蒸,下面用到的就是這個(gè) protocol 中定義的方法:

func didReceive(_ notification: UNNotification) {
  label.text = "Reminder: \(notification.request.content.body)"
  speakerLabel.shake() // 具體實(shí)現(xiàn)下載源碼可以看到
}

這個(gè)方法就是收到通知之后技扼,根據(jù)通知內(nèi)容來(lái)配置通知界面的指定方法。

初步的通知界面

看起來(lái)還不錯(cuò)嫩痰,但是中間有一大段空白剿吻,看上去不大美觀(guān)。

幸運(yùn)的是串纺,要解決這個(gè)問(wèn)題只需加 Info.plist 里再加一個(gè) key UNNotificationExtensionInitialContentSizeRatio丽旅,它定義了自定義通知界面的高寬比椰棘。這個(gè)值可能需要多試幾次來(lái)調(diào)整,對(duì)于我們目前的情況取 0.5 就比較合適了(當(dāng)寬度是 300 的時(shí)候榄笙,高度是 150)邪狞。

調(diào)整高寬比之后的界面

NotificationViewController 就是一個(gè)單純的 UIViewController 的子類(lèi),用起來(lái)跟你平常在主 app 里用普通的 viewController 是一樣的茅撞。唯一的不同點(diǎn)在于它的 userInteraction 是 disabled 的帆卓,意思是完全無(wú)法接收到用戶(hù)的點(diǎn)擊、觸摸事件乡翅。所以有部分控件是用不了的鳞疲,比如 UIScrollView、UIButton 等蠕蚜。

接受用戶(hù)操作

自定義的界面我們畫(huà)出來(lái)了尚洽,但是還有一點(diǎn)要改進(jìn):點(diǎn)擊 “Cancel” 按鈕,只會(huì)讓用戶(hù)切回到鬧鐘 app靶累,這一步有點(diǎn)多余腺毫。

上一篇文章我們講了怎么給通知加上操作按鈕:通知出現(xiàn)時(shí)可以進(jìn)行的每一項(xiàng)操作都是一個(gè) UNNotificationAction,關(guān)聯(lián)在通知 category 上挣柬。更詳細(xì)的介紹可以參考官方文檔潮酒。

UNNotificationContentExtension 這個(gè) protocol 提供了另一個(gè)處理點(diǎn)擊事件的方法:didReceive(_:completionHandler:)。我們就用這個(gè)方法邪蛔,把小喇叭的 icon 改成紅線(xiàn)劃掉的小喇叭急黎,然后把通知從 UNNotificationCenter 中移除。

func didReceive(_ response: UNNotificationResponse,
                completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {

  if response.actionIdentifier == "cancel" {
    let request = response.notification.request

    let identifiers = [request.identifier]

    // 移除后續(xù)的通知
    UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: identifiers)

    // 移除之前的通知侧到,不在用戶(hù)的通知列表里占地方了
    UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: identifiers)

    // 通知取消的視覺(jué)反饋
    speakerLabel.text = "??" 
    speakerLabel.cancelShake()

    completion(.doNotDismiss)
  }
  else {
    completion(.dismiss)
  }
}

相關(guān)的通知都移除了勃教,UI 也更新了,接下來(lái)我們需要告訴系統(tǒng)該怎么處置這個(gè)通知界面匠抗。因?yàn)槲覀兿胱層脩?hù)看到被劃掉的小喇叭故源,得到通知被取消的視覺(jué)反饋,所以要把通知留在屏幕上汞贸,因此回調(diào)里傳入 UNNotificationContentExtensionResponseOption
的一個(gè)取值 .doNotDismiss绳军。

取消通知

既然要用這個(gè)方法處理點(diǎn)擊,就得處理好每一個(gè)按鈕事件矢腻。在這個(gè)例子里门驾,我們只有一個(gè)“Cancel”按鈕。然而多柑,如果還有別的按鈕猎唁,它們的點(diǎn)擊事件也需要處理好:要么也在 extension 工程的這個(gè)方法里處理,要么回調(diào)傳 UNNotificationContentExtensionResponseOption.dismissAndForwardAction,傳給主 app 去處理诫隅。

擴(kuò)展閱讀

UserNotificationsUI 這個(gè)框架并沒(méi)有什么驚天動(dòng)地的突破腐魂,但它能讓用戶(hù)與 app 的交互更便捷。用戶(hù)可以直接對(duì)通知進(jìn)行操作逐纬,不用再切換到發(fā)出通知的 app 了蛔屹;甚至通知界面的 UI 也能動(dòng)態(tài)改變,來(lái)更好地反饋用戶(hù)操作的結(jié)果豁生。

關(guān)于通知的其他“高級(jí)”特性兔毒,我推薦看看 WWDC 2016 的演講視頻。這場(chǎng)視頻中甸箱,演講者給出了幾個(gè)蘋(píng)果官方 app 自定義通知界面的例子育叁,比如接收日程邀請(qǐng)。

原文地址:iOS 10 Day by Day :: Day 6 :: Notification Content Extensions

原作者:Sam Burnstone @sam_burnstone

ShinobiControls 官網(wǎng):ShinobiControls.com twitter : @shinobicontrols

文集地址:iOS 10 day by day 倉(cāng)薯翻譯

本文地址:http://www.reibang.com/p/001a5ab81808

譯者:戴倉(cāng)薯

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芍殖,一起剝皮案震驚了整個(gè)濱河市豪嗽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌豌骏,老刑警劉巖龟梦,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異窃躲,居然都是意外死亡计贰,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)蒂窒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)躁倒,“玉大人,你說(shuō)我怎么就攤上這事洒琢∮8龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵纬凤,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我撩嚼,道長(zhǎng)停士,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任完丽,我火速辦了婚禮恋技,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逻族。我一直安慰自己蜻底,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布聘鳞。 她就那樣靜靜地躺著薄辅,像睡著了一般要拂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上站楚,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天脱惰,我揣著相機(jī)與錄音,去河邊找鬼窿春。 笑死拉一,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的旧乞。 我是一名探鬼主播蔚润,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尺栖!你這毒婦竟也來(lái)了嫡纠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤决瞳,失蹤者是張志新(化名)和其女友劉穎货徙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體皮胡,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痴颊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屡贺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蠢棱。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖甩栈,靈堂內(nèi)的尸體忽然破棺而出泻仙,到底是詐尸還是另有隱情,我是刑警寧澤量没,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布玉转,位于F島的核電站,受9級(jí)特大地震影響殴蹄,放射性物質(zhì)發(fā)生泄漏究抓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一袭灯、第九天 我趴在偏房一處隱蔽的房頂上張望刺下。 院中可真熱鬧,春花似錦稽荧、人聲如沸橘茉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)畅卓。三九已至擅腰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間髓介,已是汗流浹背惕鼓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唐础,地道東北人箱歧。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像一膨,于是被迫代替她去往敵國(guó)和親呀邢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,104評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)豹绪、插件价淌、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評(píng)論 4 62
  • 無(wú)言獨(dú)上西樓,月如鉤瞒津。 寂寞梧桐深院鎖清秋蝉衣。 剪不斷理還亂,是離愁巷蚪。 別是一番滋味病毡,在心頭。
    半蓑煙雨任平生閱讀 327評(píng)論 0 0
  • 懂小姐步不姓懂屁柏,家里也有沒(méi)有草原啦膜。懂小姐是我多年的好友,跟她說(shuō)什么她都會(huì)說(shuō)“我懂啊”淌喻,于是大家都叫她僧家,懂小姐。 剛...
    大栗子閱讀 804評(píng)論 3 10