【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记24 popovers弹窗
上幾話中我們?cè)敿?xì)了解了幾種segue,我們也了解到了多MVC模式的幾種控制器,比如導(dǎo)航、選項(xiàng)卡和分欄,除了這三種多MVC的模式之外,還有一種popover,它跟其他三種不太一樣。首先先來(lái)認(rèn)識(shí)一下popover(彈窗)
你可以看到彈窗會(huì)有一個(gè)小箭頭指向觸發(fā)彈窗的地方:
它像一個(gè)白色的三角形。出了彈窗的區(qū)域是白色,其他區(qū)域都是灰色的,單擊其他區(qū)域的唯一功能就是讓彈窗消失。
說(shuō)popover不同的原因是,它不是一個(gè)UIViewController。它通常是presentation controller來(lái)出現(xiàn)在屏幕上的。所以popover并不真的需要一個(gè)viewcontroller,它的view是這個(gè)MVC,它可以純粹依靠presentation controller機(jī)制來(lái)做到這一點(diǎn)。
雖然它不是自己的viewcontroller,但是它依舊有所有的segue,用法并沒(méi)有區(qū)別。我們剛才在示例中看到的彈窗是ipad上的效果,在iphone它被modal替代了,IOS自動(dòng)為你配適的。但是如果你使用代理或者presentation controller,你可以影響這個(gè)配適。我們來(lái)看幻燈片:
綠色部分和其他segue沒(méi)有什么區(qū)別,但是黃色這行我從viewcontroller 過(guò)渡到popover得presentationcontroller。當(dāng)你設(shè)置自身為代理時(shí),你能做些什么呢?
我們看到代理中有兩個(gè)代理方法。第一個(gè)方法用來(lái)配適設(shè)備,默認(rèn)iphone上全屏展示,如果你把它的返回值的風(fēng)格設(shè)為none,表示不配適,那么它的彈窗會(huì)和iphone上一樣。
彈窗的另外一個(gè)重點(diǎn)是尺寸,你可能需要用一種面向?qū)ο蟮姆绞?#xff0c;也就是系統(tǒng)調(diào)用的方式來(lái)詢問(wèn)MVC合適的尺寸是多少,這只是控制器的一個(gè)屬性,你可以重寫它:
下面來(lái)展示一個(gè)Demo,讓我們的彈窗顯示瀏覽歷史,并且適應(yīng)內(nèi)容的尺寸。
我們回到Psychologist這個(gè)Demo中,在storyboard中給HappinessVeiwController右上角添加一個(gè)按鈕History用來(lái)顯示我們點(diǎn)擊的按鈕的值,這些值組成整數(shù)數(shù)組用來(lái)表達(dá)小人臉的開(kāi)心程度。注意這個(gè)按鈕不要用UIButton,用BarButtonItem,這是個(gè)輕量級(jí)的按鈕,專門放置在導(dǎo)航欄或者工具欄上。
我們需要讓這個(gè)按鈕展示一個(gè)新的控制器,所以我們向storyboard中拖一個(gè)新的控制器,然后把History按鈕和這個(gè)控制器連線,注意segue方式要選擇popover present。
和其他segue一樣,給Identifier命名,我們?nèi)∶麨镾how Diagnostic History。
雖然現(xiàn)在控制器是空白的,但是我們已經(jīng)可以運(yùn)行了。我們創(chuàng)建一個(gè)UIViewController和這個(gè)控制器對(duì)應(yīng)起來(lái),取名為TextViewController。
在storyboard中拖一個(gè)text view到新控制器中,這個(gè)textview可以顯示多行文本,設(shè)置它為不可編輯,但是可以選中,修改文本文字為24號(hào)。你會(huì)在storyboard中看到textview中有很多文字,這些是占位文字,沒(méi)有關(guān)系我們會(huì)在運(yùn)行的時(shí)候重新寫值,這些占位文字是不會(huì)顯示的。
我們?cè)诖a中創(chuàng)建多行文本的outlet。
import UIKitclass TextViewController: UIViewController {@IBOutlet weak var textView: UITextView!{didSet{textView.text = text}}var text:String = ""{didSet{textView?.text = text}} }現(xiàn)在該為我們的segue做些準(zhǔn)備了。那么這些準(zhǔn)備工作應(yīng)該在哪里做呢?顯然我們不應(yīng)該在HappinessViewController中做,因?yàn)檫@個(gè)控制器你可能是從別處拷貝來(lái)的,它的設(shè)計(jì)者希望它是專門用來(lái)管理笑臉的,它應(yīng)該對(duì)瀏覽歷史一無(wú)所知。那么我們?cè)撊绾巫瞿?#xff1f;答案是創(chuàng)建一個(gè)新的控制器,然后繼承HappinessViewController,再在其中增加瀏覽歷史的功能。 import UIKitclass DiagonsedHappinessViewController: HappinessViewController {}
那么現(xiàn)在回到storyboard中,笑臉的類應(yīng)該不再是HappinessViewController了,而是我們剛剛修改的新的類。
我們之前設(shè)置的各種outlet不會(huì)有問(wèn)題,因?yàn)樗亲宇?#xff0c;繼承了父類的所有東西,包括outlet。這就是控制器的多態(tài)性,通常你會(huì)有一個(gè)可重用的控制器,也許你想給某個(gè)特定的控制器中增加功能,這樣你就可以創(chuàng)建它的子類。
import UIKitclass DiagonsedHappinessViewController: HappinessViewController {override var happiness:Int{didSet{diagnostHistory += [happiness]}}var diagnostHistory = [Int]()private struct History{static let SegueIdentifier = "Show Diagnostic History"}override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {if let identifier = segue.identifier{switch identifier{case History.SegueIdentifier:if let tcv = segue.destinationViewController as? TextViewController{tcv.text = "\(diagnostHistory)"}default:break}}}}我們重寫了屬性happiness,這里的屬性觀察器和父類中的觀察器不會(huì)沖突,程序會(huì)先執(zhí)行父類中happiness的觀察器運(yùn)行你會(huì)發(fā)現(xiàn)這個(gè)記錄只能記錄上一次的點(diǎn)擊記錄,這是因?yàn)槲覀冎爸v過(guò)的使用segue每次打開(kāi)的MVC都是新創(chuàng)建的,所以這個(gè)瀏覽記錄需要存在我們之前講過(guò)的NSUserDefaults中。我們把diagnosticHistory改成計(jì)算屬性,靠它讀取或者寫入NSDuserDefaults。
新的代碼:
import UIKitclass DiagonsedHappinessViewController: HappinessViewController {override var happiness:Int{didSet{diagnostHistory += [happiness]}}private let defaults = NSUserDefaults.standardUserDefaults()var diagnostHistory:[Int]{get{return defaults.objectForKey(History.DefaultsKey) as? [Int] ?? []}set{defaults.setObject(newValue, forKey: History.DefaultsKey)}}private struct History{static let SegueIdentifier = "Show Diagnostic History"static let DefaultsKey = "DiagnosedHappinessViewController.History"}override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {if let identifier = segue.identifier{switch identifier{case History.SegueIdentifier:if let tcv = segue.destinationViewController as? TextViewController{tcv.text = "\(diagnostHistory)"}default:break}}}}來(lái)運(yùn)行一下看看,我們看到在iphone6上雖然出現(xiàn)了瀏覽記錄,但是popover依舊會(huì)布滿屏幕,下一個(gè)任務(wù)是修改它的尺寸了。
首先我們需要讓我們的控制器可以作為自己的彈窗代理,所以:
class DiagonsedHappinessViewController: HappinessViewController,UIPopoverControllerDelegate然后如我們之前講的,在segue中做處理,把原來(lái)的語(yǔ)句修改如下: case History.SegueIdentifier:if let tvc = segue.destinationViewController as? TextViewController,let ppc = tvc.popoverPresentationController {ppc.delegate = selftvc.text = "\(diagnostHistory)"}
可以看到popoverPresentationController是在UIViewController中的,只當(dāng)這個(gè)MVC真的在一個(gè)彈窗中的時(shí)候它才會(huì)返回,否則返回nil,然后我們把代理設(shè)為自己,這是我們第一次控制系統(tǒng)的代理。之后我們實(shí)現(xiàn)控制尺寸的代理方法; func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!, traitCollection: UITraitCollection!) -> UIModalPresentationStyle {return UIModalPresentationStyle.None}
這個(gè)代理的返回表示我們不做任何配適,運(yùn)行看看:
完整代碼如下:
import UIKitclass DiagonsedHappinessViewController: HappinessViewController,UIPopoverPresentationControllerDelegate{override var happiness:Int{didSet{diagnostHistory += [happiness]}}private let defaults = NSUserDefaults.standardUserDefaults()var diagnostHistory:[Int]{get{return defaults.objectForKey(History.DefaultsKey) as? [Int] ?? []}set{defaults.setObject(newValue, forKey: History.DefaultsKey)}}private struct History{static let SegueIdentifier = "Show Diagnostic History"static let DefaultsKey = "DiagnosedHappinessViewController.History"}override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {if let identifier = segue.identifier{switch identifier{case History.SegueIdentifier:if let tvc = segue.destinationViewController as? TextViewController,let ppc = tvc.popoverPresentationController {ppc.delegate = selftvc.text = "\(diagnostHistory)"}default:break}}}func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!, traitCollection: UITraitCollection!) -> UIModalPresentationStyle {return UIModalPresentationStyle.None}}現(xiàn)在還有最后一個(gè)步驟,彈窗的窗口有點(diǎn)大,我們需要它的尺寸適應(yīng)彈窗中的內(nèi)容的大小。這次我們需要到TextViewController中去做修改:
override var preferredContentSize:CGSize {get{if textView != nil && presentingViewController != nil{//presentationViewController也是父類的屬性,表示當(dāng)前顯示的頁(yè)面return textView.sizeThatFits(presentingViewController!.view.bounds.size)} else {return super.preferredContentSize //無(wú)論如何要考慮所有情況}}set{super.preferredContentSize = newValue}}
我們重寫父類中的這個(gè)屬性
然后再次運(yùn)行:
成功了!
總結(jié)
以上是生活随笔為你收集整理的【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记24 popovers弹窗的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: XState Viz 可视化和调试状态机
- 下一篇: hdu水仙花