Start Developing iOS Apps (Swift)->使用視圖控制器(二)

創(chuàng)建手勢(shì)識(shí)別器

image view不是控件液茎,它沒(méi)有被設(shè)計(jì)成像button或者slider那樣對(duì)輸入作出響應(yīng)。例如免钻,你不能簡(jiǎn)單的創(chuàng)建一個(gè)方法莫秆,讓它能夠在image view 被用戶點(diǎn)擊的時(shí)候被觸發(fā)。(如果你在剛才拖拽image view的時(shí)候稍加留意催什,你會(huì)發(fā)現(xiàn)彈出對(duì)話框的Connection字段不能選擇Action涵亏。)

幸運(yùn)的是,只要通過(guò)添加手勢(shì)識(shí)別器(gesture recognizers)就能讓視圖輕松的獲得和控件一樣的能力。手勢(shì)識(shí)別器是你附加在視圖上的對(duì)象气筋,它可以讓視圖以控件的方式響應(yīng)用戶拆内。手勢(shì)識(shí)別器解釋觸摸,判斷它們是否符合特殊的手勢(shì)宠默,例如滑動(dòng)(swipe)矛纹、捏合(pinch)、或者旋轉(zhuǎn)(rotation)光稼。你能夠?qū)懸粋€(gè)方法,當(dāng)手勢(shì)識(shí)別器識(shí)別到它被分配的手勢(shì)時(shí)這個(gè)方法會(huì)被調(diào)用孩等。這正是你想為image view做的艾君。

附加一個(gè)輕拍(tap)手勢(shì)識(shí)別器(UITapGestureRecognizer)給image view,它將識(shí)別用戶對(duì)image view 的輕拍手勢(shì)肄方。在storyboard中你很容易做到這點(diǎn)冰垄。

添加輕拍手勢(shì)識(shí)別器給你的image view

  1. 打開(kāi)Object library
  2. 在Object library中,在過(guò)濾字段中輸入tap gesture快速找到Tap Gesutre Recognizer 對(duì)象权她。
  3. 從Object library拖拽Tap Gesture Recognizer對(duì)象到你的場(chǎng)景虹茶,放到image view 的上面。


    image: ../Art/WWVC_gesturerecognizer_drag_2x.png

    Tap Gesture Recognizer對(duì)象出現(xiàn)在了菜品的場(chǎng)景dock中隅要。


    image: ../Art/WWVC_scenedock_2x.png

連接手勢(shì)識(shí)別器到代碼

現(xiàn)在連接手勢(shì)識(shí)別器到代碼中的action方法蝴罪。

連接手勢(shì)識(shí)別器到ViewController.swift代碼

  1. 按住Control鍵,從場(chǎng)景dock的手勢(shì)識(shí)別器處拖拽一條線到右側(cè)的編輯器的代碼處步清,停在如圖所示的位置要门。


    image: ../Art/WWVC_gesturerecognizer_dragaction_2x.png
  2. 在彈出的對(duì)話框中,在Connection字段選擇Action廓啊。
  3. Name字段欢搜,填入selectImageFromPhotoLibrary。
  4. Type字段谴轮,選擇UITapGestureRecognizer炒瘟。
    你的對(duì)話框看起來(lái)像這樣:


    image: ../Art/WWVC_gesturerecognizer_addaction_2x.png
    image: ../Art/WWVC_gesturerecognizer_addaction_2x.png
  5. 點(diǎn)擊連接。
@IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
}   

創(chuàng)建一個(gè)Image Picker來(lái)響應(yīng)用戶的點(diǎn)擊

當(dāng)用戶點(diǎn)擊image view的時(shí)候第步,他們應(yīng)該可以從相冊(cè)中選擇一張照片疮装,或者自己拍攝一張。幸運(yùn)的是雌续,UIImagePickerController類已經(jīng)有了這些功能斩个。一個(gè)image picker controller(圖片拾取控制器) 管理用于拍攝照片和選擇圖片的用戶界面,以便在你的應(yīng)用中使用驯杜。就像你使用text field的時(shí)候需要text field delegate一樣受啥,你在使用image picker的時(shí)候也需要image picker controller delegate。這個(gè)委托協(xié)議的名字是UIImagePickerControllerDelegate,你要聲明為image picker controller的委托的對(duì)象是ViewController滚局。

首先居暖,ViewController需要采用UIImagePickerControllerDelegate協(xié)議。由于ViewController將要承擔(dān)顯示image picker controller的責(zé)任藤肢,所以它也需要采用UINavigationControllerDelegate協(xié)議太闺,這樣就可以讓ViewController承擔(dān)一些基本的導(dǎo)航功能。

采用UIImagePickerControllerDelegate和UINavigationControllerDelegate協(xié)議

  1. 回到標(biāo)準(zhǔn)編輯器嘁圈。


    image: ../Art/standard_toggle_2x.png
  2. 在project navigator省骂,選擇ViewController.swift。
  3. 在ViewController.swift中最住,找到class這行钞澳。
class ViewController: UIViewController, UITextFieldDelegate {
  1. 在UITextFieldDelegate后面,添加逗號(hào)和UIImagePickerControllerDelegate來(lái)采用這個(gè)協(xié)議涨缚。
class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate {
  1. 在UIImagePickerControllerDelegate后面轧粟,添加逗號(hào)和UINavigationControllerDelegate來(lái)采用這個(gè)協(xié)議。

現(xiàn)在脓魏,回到你定義的action方法兰吟,selectImageFromPhotoLibrary(_:),來(lái)完成它的實(shí)現(xiàn)茂翔。

實(shí)現(xiàn)名為selectImageFromPhotoLibrary(_:)的 action 方法

  1. 在ViewController.swift中混蔼,找到你之前添加的selectImageFromPhotoLibrary(_:)方法。
@IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
}   
  1. 在這個(gè)方法的兩個(gè)花括號(hào)({ })之間檩电,加入如下代碼:
// Hide the keyboard.
nameTextField.resignFirstResponder()

這個(gè)代碼確保在text filed是第一響應(yīng)者的時(shí)候用戶點(diǎn)擊了image view拄丰,鍵盤會(huì)消失(也就是text field注銷了第一響應(yīng)者)。This code ensures that if the user taps the image view while typing in the text field, the keyboard is dismissed properly.

  1. 添加下面這些代碼來(lái)創(chuàng)建一個(gè)image picker controller俐末。
// UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()   
  1. 添加代碼料按。
// Only allow photos to be picked, not taken.
imagePickerController.sourceType = .photoLibrary

這行代碼設(shè)置了image picker controller的源,或者說(shuō)要從何處獲取圖片卓箫。這個(gè).photoLibrary選項(xiàng)使用的是模擬器的相冊(cè)载矿。
imagePickerController.sourceType的類型是UIImagePickerControllerSourceType,它是一個(gè)枚舉類型(enumeration)烹卒。這意味著你可以直接使用縮寫(xiě)形式.photoLibrary 來(lái)表示UIImagePickerControllerSourceType.photoLibrary闷盔。回想一下旅急,只要知道是枚舉值類型就可以采用這種縮寫(xiě)形式逢勾。

  1. 添加代碼來(lái)設(shè)置image picker controller的委托為ViewController。
// Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self

6緊接著藐吮,添加代碼

present(imagePickerController, animated: true, completion: nil) 

present(_:animated:completion:)是一個(gè)在ViewController上調(diào)用的方法溺拱。雖然沒(méi)有明確的寫(xiě)逃贝,但是這個(gè)方法是有一個(gè)隱式的self對(duì)象執(zhí)行的。這個(gè)方法請(qǐng)求ViewController呈現(xiàn)由imagePickerController定義的一個(gè)視圖控制器迫摔。把a(bǔ)nimated參數(shù)值設(shè)為true會(huì)以動(dòng)畫(huà)的方式來(lái)呈現(xiàn)image picker controller沐扳。completion參數(shù)是指完成處理程序(completion handle),是在這個(gè)方法執(zhí)行完畢之后執(zhí)行的一段代碼句占。因?yàn)槟氵€不需要做這些沪摄,所以把它設(shè)置為nil就好。

現(xiàn)在你的selectImageFromPhotoLibrary(_:)方法看起來(lái)是這樣的:

@IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
            
     // Hide the keyboard.
     nameTextField.resignFirstResponder()
            
    // UIImagePickerController is a view controller that lets a user pick media from their photo library.
     let imagePickerController = UIImagePickerController()
            
     // Only allow photos to be picked, not taken.
    imagePickerController.sourceType = .photoLibrary
            
     // Make sure ViewController is notified when the user picks an image.
    imagePickerController.delegate = self
    present(imagePickerController, animated: true, completion: nil)
}

當(dāng)image picker controller被呈現(xiàn)之后纱烘,你可以通過(guò)委托方法來(lái)和它互動(dòng)杨拐。要想給用戶選擇照片的能力,你需要實(shí)現(xiàn)兩個(gè)定義在UIImagePickerControllerDelegate:里的委托方法:

func imagePickerControllerDidCancel(_ picker: UIImagePickerController)
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])

第一個(gè)方法擂啥,imagePickerControllerDidCancel(_:)戏阅,會(huì)在用戶點(diǎn)擊圖像選擇器(image picker)的取消(Cancel)按鈕的時(shí)候調(diào)用。這個(gè)方法可以讓你有機(jī)會(huì)關(guān)閉UIImagePickerController(并且可以選擇任何有必要的清理)啤它。

實(shí)現(xiàn)imagePickerControllerDidCancel(_:)方法

  1. 在ViewController.swift中,在//MARK: Actions部分上面舱痘,添加:
//MARK: UIImagePickerControllerDelegate

這個(gè)注釋幫助你導(dǎo)航到代碼位置变骡。

  1. 緊跟著注釋,添加下面這個(gè)方法:
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
}
  1. 在這個(gè)方法中芭逝,輸入下面代碼:
// Dismiss the picker if the user canceled.
dismiss(animated: true, completion: nil)    

這個(gè)代碼會(huì)帶動(dòng)畫(huà)的移除image picker controller塌碌。

你的imagePickerControllerDidCancel(_:)方法看上去是這樣的:

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    // Dismiss the picker if the user canceled.
    dismiss(animated: true, completion: nil)
}

第二個(gè)方法需要實(shí)現(xiàn)的UIImagePickerControllerDelegate,imagePickerController(_:didFinishPickingMediaWithInfo:)旬盯,在你選擇照片的時(shí)候調(diào)用台妆。這個(gè)方法讓你有機(jī)會(huì)對(duì)從選擇器來(lái)的圖片做一些事。本例中胖翰,你將選擇圖片接剩,然后顯示在image view上。

實(shí)現(xiàn)imagePickerController(_:didFinishPickingMediaWithInfo:) 方法

  1. 在imagePickerControllerDidCancel(_:)方法下面添加方法:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
}       
  1. 在這個(gè)方法中添加如下代碼:
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}

這個(gè)info字典始終包含從拾取器獲取的原圖萨咳。它也可能包含一個(gè)原圖的編輯版本懊缺,如果有的話。簡(jiǎn)單起見(jiàn)培他,你將使用沒(méi)有修改的原圖鹃两。
這段代碼從info字典中訪問(wèn)原始未編輯的圖片。它安全地解包由字典返回的可選對(duì)象舀凛,并把它轉(zhuǎn)化為UIImage對(duì)象俊扳。期望是解包和轉(zhuǎn)換都沒(méi)有錯(cuò)誤。如果有錯(cuò)猛遍,就相當(dāng)于應(yīng)用有bug馋记,需要在設(shè)計(jì)的時(shí)候修補(bǔ)它号坡。 fatalError()方法在控制臺(tái)打印一個(gè)錯(cuò)誤信息,包括info字典的內(nèi)容抗果,然后使應(yīng)用終——防止應(yīng)用繼續(xù)處于無(wú)效狀態(tài)筋帖。

  1. 添加下面這行代碼,它把選中的圖片設(shè)置到image view上冤馏。
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage    
  1. 添加下面代碼來(lái)移除image picker日麸。
// Dismiss the picker.
dismiss(animated: true, completion: nil)    

你的imagePickerController(_:didFinishPickingMediaWithInfo)方法看上去是這樣的:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
            
    // The info dictionary may contain multiple representations of the image. You want to use the original.
    guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
          fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
          }
            
    // Set photoImageView to display the selected image.
    photoImageView.image = selectedImage
            
    // Dismiss the picker.
    dismiss(animated: true, completion: nil)
}

檢查點(diǎn):運(yùn)行應(yīng)用。當(dāng)你點(diǎn)擊image view的時(shí)候發(fā)生了什么逮光?

image: ../Art/WWVC_app_abort_2x.png

應(yīng)用以SIGABRT信號(hào)終止代箭。這意味著發(fā)生了一個(gè)足以導(dǎo)致應(yīng)用終止的嚴(yán)重錯(cuò)誤。在本例中涕刚,當(dāng)你嘗試顯示image picker的時(shí)候這個(gè)問(wèn)題會(huì)發(fā)生嗡综。系統(tǒng)在訪問(wèn)photo library之前必須詢問(wèn)用戶是否允許。在iOS 10之后杜漠,你必須提供photo library使用描述极景。這個(gè)描述解釋了你為什么想要訪問(wèn)photo library。

添加一個(gè)photo library使用描述

  1. 在project navigator驾茴,選擇Info.plist盼樟。
    Xcode在編輯器區(qū)域顯示屬性列表(property list)。屬性列表是一個(gè)結(jié)構(gòu)化的文本文件锈至,它包含了關(guān)于應(yīng)用的必要配置信息晨缴。屬性列表的根是一個(gè)字典,它保存一組預(yù)定義的鍵和它們的值峡捡。


    image: ../Art/WWVC_Property_List_Editor_2x.png

進(jìn)一步探索
更多關(guān)于info.plist的信息击碗,詳見(jiàn)Information Property List Key Reference。

  1. 如果屬性列表最后一個(gè)項(xiàng)目是數(shù)組们拙,確保它是折疊的稍途。如果你在一個(gè)展開(kāi)的數(shù)組上添加項(xiàng)目,它會(huì)添加為一個(gè)子項(xiàng)目砚婆。如果你添加項(xiàng)目到折疊的數(shù)組晰房,那么就會(huì)添加一個(gè)兄弟數(shù)組。
  2. 添加新項(xiàng)目射沟,鼠標(biāo)懸停在屬性列表的最后一個(gè)項(xiàng)目上殊者,當(dāng)出現(xiàn)添加按鈕(Add button)的時(shí)候,點(diǎn)擊它(或者選擇Editor > Add Item)验夯。


    image: ../Art/WWVC_addInfoPlistItem_2x.png
  3. 在彈出的菜單中猖吴,滾動(dòng)然后選擇 Privacy - Photo Library Usage Description。
    image: ../Art/WWVC_addphotolibrarydescription_2x.png
  4. 在新行中挥转,確保Type (類型)設(shè)置的是String海蔽。然后共屈,雙擊值區(qū)域,并鍵入Allows you to add photos to your meals.


    image: ../Art/WWVC_addingDescriptionString_2x.png
  5. 當(dāng)你輸入完描述文件后党窜,按下回車鍵拗引。

檢查點(diǎn):再次運(yùn)行應(yīng)用。這次你應(yīng)該能夠點(diǎn)擊image view來(lái)顯示一個(gè)image picker幌衣。你需要在彈出的警告框上點(diǎn)擊OK矾削,這個(gè)警告框詢問(wèn)是否給FoodTracker應(yīng)用訪問(wèn)Photos的許可。然后豁护,你可以點(diǎn)擊Cancel 按鈕來(lái)移除picker哼凯,或者打開(kāi)相冊(cè)然后點(diǎn)擊一張圖片讓它顯示在image view上。

image: ../Art/WWVC_sim_imagepicker_2x.png

如果你看遍了模擬器中照片楚里,你會(huì)發(fā)現(xiàn)它沒(méi)有食品的照片断部。你可以直接添加自己的圖片到模擬器,以便使用合適的內(nèi)容來(lái)測(cè)試FoodTracker應(yīng)用班缎。你可以在下載文件的Images文件夾里找到圖片蝴光,下載地址在本課最后,或者使用你自己的圖片达址。

添加圖片到iOS模擬器

  1. 如有必要虱疏,在模擬器中運(yùn)行應(yīng)用。
  2. 在你的電腦中苏携,選擇你想要添加的圖片。
  3. 拖拽圖片到模擬器对粪。


    image: ../Art/WWVC_sim_dragphoto_2x.png

模擬器打開(kāi)Photos應(yīng)用右冻,并且顯示你添加的圖片。

image: ../Art/WWVC_sim_choosephoto_2x.png

檢查點(diǎn):運(yùn)行應(yīng)用著拭。你應(yīng)該能輕拍image view來(lái)顯示一個(gè)image picker纱扭。打開(kāi)相冊(cè),點(diǎn)擊你添加到模擬器中的圖片儡遮,選擇它來(lái)設(shè)置iamge view的圖片乳蛾。

image: ../Art/WWVC_sim_selectedphoto_2x.png

小結(jié)

在本課中,你學(xué)到了關(guān)于視圖控制器生命周期方法鄙币,并且使用它們配置了你的視圖控制器內(nèi)容肃叶。你也學(xué)習(xí)了如何給視圖添加手勢(shì)識(shí)別器,并且知道如何從photo library中選擇照片十嘿。場(chǎng)景開(kāi)始看上去像一個(gè)真實(shí)的應(yīng)用了因惭。在下一課中,你將添加自定義的控件到場(chǎng)景绩衷。

注意
想看本課的完整代碼蹦魔,下載這個(gè)文件并在Xcode中打開(kāi)激率。

下載文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市勿决,隨后出現(xiàn)的幾起案子乒躺,更是在濱河造成了極大的恐慌,老刑警劉巖低缩,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘉冒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡表制,警方通過(guò)查閱死者的電腦和手機(jī)健爬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)么介,“玉大人娜遵,你說(shuō)我怎么就攤上這事∪蓝蹋” “怎么了设拟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)久脯。 經(jīng)常有香客問(wèn)我纳胧,道長(zhǎng),這世上最難降的妖魔是什么帘撰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任跑慕,我火速辦了婚禮,結(jié)果婚禮上摧找,老公的妹妹穿的比我還像新娘核行。我一直安慰自己,他們只是感情好蹬耘,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布芝雪。 她就那樣靜靜地躺著,像睡著了一般综苔。 火紅的嫁衣襯著肌膚如雪惩系。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天如筛,我揣著相機(jī)與錄音堡牡,去河邊找鬼。 笑死杨刨,一個(gè)胖子當(dāng)著我的面吹牛悴侵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拭嫁,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼可免,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抓于!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起浇借,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捉撮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后妇垢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體巾遭,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年闯估,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灼舍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涨薪,死狀恐怖骑素,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刚夺,我是刑警寧澤献丑,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站侠姑,受9級(jí)特大地震影響创橄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莽红,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一妥畏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧安吁,春花似錦醉蚁、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)郭赐。三九已至薪韩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捌锭,已是汗流浹背俘陷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留观谦,地道東北人拉盾。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像豁状,于是被迫代替她去往敵國(guó)和親捉偏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子倒得,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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