你在本系列文章中將會學到
- 如何安裝和使用cocoapods來集成第三方庫
- 如何搭建一個類似于iOS短信app的界面,以及使用SnapKit來用代碼設置autolayout
- 如何使用Parse云服務平臺存儲和同步聊天信息,學習相應地數據庫知識
- 如何使用Parse的遠程推送功能
- 如何使用Alamofire實現與智能機器人聊天功能
初始項目下載地址:
百度網盤下載地址
配置初始項目
1.cocoapods的安裝
cocoapods的安裝是通過ruby,幸運的是Mac電腦都是默認安裝ruby的,所以安裝ruby的過程就省去了,唯一的前提就是安裝Xcode的CommandLineTools。
commandLineTools的安裝也很簡單,只要在終端輸入以下命令:
$ xcode-select --install
如果確實沒有安裝commandLineTools會提示你要安裝它,點安裝就可以開始下載,然后等待下載完成后安裝即可
下面開始安裝cocoapods,本來只需要簡單地在終端輸入以下命令即可:
$ sudo gem install cocoapods
但是由于中國的互聯網是"自由的"。??瓤?,所以呢,你要改變gem的默認下載源:
$ gem sources -a https://ruby.taobao.org
看到以下結果
http://ruby.taobao.org added to sources
將淘寶的ruby源加入進來,看來淘寶也不光是賣東西哈,也是對開發者做了一些貢獻的~
刪除原來的下載源:
$ gem sources -r https://rubygems.org/
看到以下結果就說明已經成功
https://rubygems.org/ removed from sources
然后呢,就可以愉快地安裝上cocoapods了!
$ sudo gem install cocoapods
Password:(你的管理員密碼,這里不會顯示出來)
Fetching: cocoapods-core-0.38.2.gem (100%)
Successfully installed cocoapods-core-0.38.2
Fetching: claide-0.9.1.gem (100%)
Successfully installed claide-0.9.1
Fetching: xcodeproj-0.26.3.gem (100%)
Successfully installed xcodeproj-0.26.3
Fetching: cocoapods-downloader-0.9.3.gem (100%)
Successfully installed cocoapods-downloader-0.9.3
Fetching: cocoapods-stats-0.5.3.gem (100%)
Successfully installed cocoapods-stats-0.5.3
Fetching: cocoapods-try-0.4.5.gem (100%)
Successfully installed cocoapods-try-0.4.5
Fetching: cocoapods-trunk-0.6.4.gem (100%)
Successfully installed cocoapods-trunk-0.6.4
Fetching: molinillo-0.3.1.gem (100%)
Successfully installed molinillo-0.3.1
Fetching: cocoapods-0.38.2.gem (100%)
Successfully installed cocoapods-0.38.2
Parsing documentation for cocoapods-core-0.38.2
Installing ri documentation for cocoapods-core-0.38.2
Parsing documentation for claide-0.9.1
Installing ri documentation for claide-0.9.1
Parsing documentation for xcodeproj-0.26.3
Installing ri documentation for xcodeproj-0.26.3
Parsing documentation for cocoapods-downloader-0.9.3
Installing ri documentation for cocoapods-downloader-0.9.3
Parsing documentation for cocoapods-stats-0.5.3
Installing ri documentation for cocoapods-stats-0.5.3
Parsing documentation for cocoapods-try-0.4.5
Installing ri documentation for cocoapods-try-0.4.5
Parsing documentation for cocoapods-trunk-0.6.4
Installing ri documentation for cocoapods-trunk-0.6.4
Parsing documentation for molinillo-0.3.1
Installing ri documentation for molinillo-0.3.1
Parsing documentation for cocoapods-0.38.2
Installing ri documentation for cocoapods-0.38.2
9 gems installed
OK,cocoapods順利安裝完畢!
2.cocoapods的使用
那么cocoapods怎么用呢,當然第一次使用會覺得它非常麻煩,但是呢漸漸地你會發現這是一個非常好用的工具,可以說是iOS開發者必備!
首先創建我們的Xcode工程:File/New/Project.../Single View Application
起名叫圖靈聊天。
我們將要使用圖靈機器人的api進行開發:
圖靈機器人官網
打開項目,新建一個空文件:File/New/File.../ iOS/Others/Empty
起名叫Podfile,這一點非常重要,因為這是cocoapods的配置文件,也就是指定你要使用哪些第三方庫!
我們要使用以下幾個庫:
- Alamofire,網絡請求庫,用來調用圖靈機器人的api
- SnapKit,用代碼進行autolayout設置
- Parse ,Parse云服務平臺的SDK
- ParseUI,Parse提供的便捷UI組件
在Podfile中,輸入以下代碼:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.4'
use_frameworks!
指定下載源,指定平臺版本,使用framework進行集成
由于swift的特殊性,某些第三方庫必須使用framework來集成,但是這樣也有一個好處,我也是最近才發現,就是Parse和ParseUI其實是OC編寫的庫,但是呢卻不需要OC-Swift的橋接文件了!可以直接當做swift庫來使用!
pod 'Alamofire', '~> 1.3'
pod 'SnapKit', '~> 0.12.0'
pod 'Parse','~>1.7.1'
pod 'ParseUI','~>1.1.3'
選擇指定的第三方庫及其版本
開始安裝第三方庫,打開終端,將當前目錄轉到Podfile所在目錄:
$ cd <Podfile所在目錄>
輸入以下命令開始配置第三方庫:
$ pod install
Analyzing dependencies
Downloading dependencies
Using Alamofire (1.3.1)
Using Bolts (1.2.1)
Using Parse (1.7.5.3)
Using ParseUI (1.1.4)
Using SnapKit (0.12.0)
Generating Pods project
Integrating client project
Sending stats
然后等待幾分鐘,如果一切正常,沒有出現錯誤的話,打開項目文件后你會看到workspace的文件,以后都要使用這個文件來打開項目。
打開項目,看一下項目的結構:
點一下Pods項目,你會發現所需的framework已經編譯好了,只要在使用前import他們就可以了:
OK,到此我們的項目就配置好了,在我們開始搭建UI之前,先了解一下Parse的使用和一些必要配置
配置Parse
首先打開Parse的官網:
點我
注冊一個新的用戶,點擊右上角的sign up :
以上用戶名只是示例,但是app名稱輸入TuringChat。
注冊完畢后,用你剛才注冊的用戶名登陸,應該會出現以下界面:
然后導入我們的示例數據:
點我下載
點擊import按鈕:
選擇剛才下載的文件:
然后剛才導入的數據就會顯示出來,并自動新建了一個數據庫類:Messages
我們來看一眼Messages類里都有什么:
名稱 | 類型 | 含義 | 備注 |
---|---|---|---|
objectId | String | 系統默認鍵 | 每一條數據都對應一個獨一無二的id |
incoming | Boolean | 用來確定該條信息是發送給我們的還是發送出去的 | true就是發送來的反之就是我們發送出去的 |
sentDate | Date | 消息發送時間 | 無 |
text | String | 消息的內容 | 無 |
createdAt | Date | 系統默認鍵 | 數據創建時間 |
updatedAt | Date | 系統默認鍵 | 數據上一次更新的時間 |
ACL | ACL | 系統默認鍵 | 數據的讀寫模式 |
接下來我們來測試一下能否讀取到這些數據,首先要獲得該app的application ID和Client Key:
紅線劃掉的那兩行就是我們需要的。
然后打開項目中的AppDelegate.swift,增加對Parse庫的引用:
import Parse
找到以下方法
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
在里面添加代碼:
Parse.setApplicationId("CYdFL9mvG8jHqc4ZA5PJsWMInBbMMun0XCoqnHgf", clientKey: "6tGOC1uIKeYp5glvJE6MXZOWG9pmLtMuIUdh2Yzo")
連接Parse的服務器
var query = PFQuery(className: "Messages")
query.orderByAscending("sentDate")
query.findObjectsInBackgroundWithBlock { (objects,error) -> Void in
for object in objects as! [PFObject]{
let incoming:Bool = object["incoming"] as! Bool
let text:String = object["text"] as! String
let sentDate:NSDate = object["sentDate"] as! NSDate
println("\\(object.objectId!)\\n\\(incoming)\\n\\(text)\\n\\(sentDate)")
}
}
新建查詢,查詢我們剛才所建的Messages
類,用findObjectsInBackgroundWithBlock
方法取出查詢結果,并用一個循環全部打印出來。
cmd+R運行一下,如果沒有問題會輸出類似下面的內容:
oYtildSAOz
false
你叫什么名字?
2015-08-28 06:42:00 +0000
LX7kxmmiEp
true
我叫靈靈,聰明又可愛的靈靈
2015-08-28 06:43:00 +0000
p62dmgGIAS
false
你愛不愛我?
2015-08-28 06:43:00 +0000
oWReOM43Nf
true
愛你么么噠
2015-08-28 06:44:00 +0000
mtl2BGt3Mu
false
今天北京天氣如何?
2015-08-29 03:59:00 +0000
DikAu5P2Nn
true
北京:08/29 周六,20-29° 28° 雷陣雨 微風小于3級;08/30 周日,19-27° 雷陣雨 微風小于3級;08/31 周一,19-27° 雷陣雨 微風小于3級;09/01 周二,20-26° 雷陣雨 微風小于3級;
2015-08-29 03:59:01 +0000
很好,我們的數據庫連接沒有問題,那么下面開始搭建我們的UI。
搭建UI
我們需要搭建的UI只是聊天頁面,我們首先來看一看聊天頁面的結構:
界面主要由以下三個部分組成
那么這三部分怎樣去實現呢,我先向大家做一些簡單的介紹:
1.導航欄
這一部分實現比較簡單,只要把視圖控制器嵌套在一個導航控制器(UINavigationController)中即可,然后對其外觀進行一些定制化操作。
2.聊天窗口
這一部分用UITableView來構建。仔細觀察你會發現這里一共有三種UITableViewCell:
- 用來顯示消息發送日期的cell
- 發送消息氣泡的cell
- 接收消息氣泡的cell
但其實我們只需要兩個,因為后兩種cell區別只是是顏色和位置,我們只要判斷一下該消息是發送的還是接收的,然后相應進行處理即可!
兩種cell都是用的以下這個素材:
MessageBubble.png
但是,你會問,它為啥是黑色的!怎么讓他變成圖中的兩種顏色呢?還有明明聊天氣泡的大小是不定的,這樣一張圖怎么能滿足所有尺寸呢?
有疑問很好,因為它可以成為你學習的動力,我們會在接下來向大家解釋這是如何實現的!Be patient!
3.輸入框
這里我們要通過重寫UIResponder
類的inputAccessoryView
屬性來自定義我們的輸入框,這樣做的好處是我們的輸入框會和系統的鍵盤結合起來,可以讓其成為第一響應者(first responder),一旦它成為第一響應者,我們自定義的輸入框會跟隨鍵盤一同彈出和收回,就像真正的短信app那樣,這個方法比我有一篇文章所寫的實現類似微信的輸入框跟隨鍵盤彈出的效果的方法還要更好一些,所以說方法不是絕對的,因為你總是能夠找到更好的方法,所以,編程的時候要經常在腦子里想"嗯,一定還有更好的方法"。
嗯好嘞,廢話不多說,下面我們就來一步一步地一一實現它們!
首先從最簡單的做起,實現自定義導航欄:
打開初始項目你會看到模板文件已經全部建好:
找到AppDelegate.swift文件中的以下方法:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
在其中添加如下代碼:
var ChatVC:ChatViewController = ChatViewController()
ChatVC.title = "靈靈"
UINavigationBar.appearance().tintColor = UIColor(red: 0.05, green: 0.47, blue: 0.91, alpha: 1.0)
UINavigationBar.appearance().barTintColor = UIColor(red: 0.05, green: 0.47, blue: 0.91, alpha: 1.0)
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
var navigationVC:UINavigationController = UINavigationController(rootViewController: ChatVC)
let frame = UIScreen.mainScreen().bounds
window = UIWindow(frame: frame)
window!.rootViewController = navigationVC
window!.makeKeyAndVisible()
設置app啟動時顯示我們自定義的視圖控制器,并設置一下導航欄的外觀。
ok,第一部分完成。
接下來我們來實現一下第三部分:輸入框,我們要把最難的第二部分留在最后( ⊙ o ⊙ )
打開ChatViewController.swift文件:
添加一些全局常量,在import下面class的定義之上:
let messageFontSize: CGFloat = 17
let toolBarMinHeight: CGFloat = 44
第一個是消息所用的字體大小,第二個是我們輸入框的高度。
添加一些組成輸入框的組件:
var toolBar: UIToolbar!
var textView: UITextView!
var sendButton: UIButton!
toolBar用來承載輸入框中的組件,之所以用UIToolbar是因為它默認出現在屏幕最下方,就像你的短信輸入框那樣。
textView是我們輸入文字的地方,而sendButton則是我們的發送按鈕。
下面實現我們重寫的inputAccessoryView,在這之前先讓我們的視圖控制器遵循UITextViewDelegate
協議:
class ViewController: UIViewController,UITextViewDelegate {
....
....
}
下面添加以下代碼來聲明對inputAccessoryView的重寫:
override var inputAccessoryView: UIView! {
}
用get的方式將輸入框的組件進行配置:
在大括號內部添加代碼:
get {
if toolBar == nil {
toolBar = UIToolbar(frame: CGRectMake(0, 0, 0, toolBarMinHeight-0.5))
textView = InputTextView(frame: CGRectZero)
textView.backgroundColor = UIColor(white: 250/255, alpha: 1)
textView.delegate = self
textView.font = UIFont.systemFontOfSize(messageFontSize)
textView.layer.borderColor = UIColor(red: 200/255, green: 200/255, blue: 205/255, alpha:1).CGColor
textView.layer.borderWidth = 0.5
textView.layer.cornerRadius = 5
// textView.placeholder = "Message"
textView.scrollsToTop = false
textView.textContainerInset = UIEdgeInsetsMake(4, 3, 3, 3)
toolBar.addSubview(textView)
sendButton = UIButton.buttonWithType(.System) as! UIButton
sendButton.enabled = false
sendButton.titleLabel?.font = UIFont.boldSystemFontOfSize(17)
sendButton.setTitle("發送", forState: .Normal)
sendButton.setTitleColor(UIColor(red: 142/255, green: 142/255, blue: 147/255, alpha: 1), forState: .Disabled)
sendButton.setTitleColor(UIColor(red: 0.05, green: 0.47, blue: 0.91, alpha: 1.0), forState: .Normal)
sendButton.contentEdgeInsets = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 6)
sendButton.addTarget(self, action: "sendAction", forControlEvents: UIControlEvents.TouchUpInside)
toolBar.addSubview(sendButton)
// 對組件進行Autolayout設置
textView.setTranslatesAutoresizingMaskIntoConstraints(false)
sendButton.setTranslatesAutoresizingMaskIntoConstraints(false)
toolBar.addConstraint(NSLayoutConstraint(item: textView, attribute: .Left, relatedBy: .Equal, toItem: toolBar, attribute: .Left, multiplier: 1, constant: 8))
toolBar.addConstraint(NSLayoutConstraint(item: textView, attribute: .Top, relatedBy: .Equal, toItem: toolBar, attribute: .Top, multiplier: 1, constant: 7.5))
toolBar.addConstraint(NSLayoutConstraint(item: textView, attribute: .Right, relatedBy: .Equal, toItem: sendButton, attribute: .Left, multiplier: 1, constant: -2))
toolBar.addConstraint(NSLayoutConstraint(item: textView, attribute: .Bottom, relatedBy: .Equal, toItem: toolBar, attribute: .Bottom, multiplier: 1, constant: -8))
toolBar.addConstraint(NSLayoutConstraint(item: sendButton, attribute: .Right, relatedBy: .Equal, toItem: toolBar, attribute: .Right, multiplier: 1, constant: 0))
toolBar.addConstraint(NSLayoutConstraint(item: sendButton, attribute: .Bottom, relatedBy: .Equal, toItem: toolBar, attribute: .Bottom, multiplier: 1, constant: -4.5))
}
return toolBar
}
你會發現有一個錯誤,這是因為我們的InputTextView是一個單獨定義的類,它還沒有定義,我們在之后會對他做一些操作,目前先不用管它,不過我們先把它定義出來,在視圖控制器類之外定義該類:
class InputTextView: UITextView {
}
還有一個問題,用系統默認的代碼實現autolayout看起來很難理解,所以這里可以用第三方庫SnapKit來實現,把上面設置autolayout的代碼替換成以下代碼:
textView.setTranslatesAutoresizingMaskIntoConstraints(false)
sendButton.setTranslatesAutoresizingMaskIntoConstraints(false)
textView.snp_makeConstraints({ (make) -> Void in
make.left.equalTo(self.toolBar.snp_left).offset(8)
make.top.equalTo(self.toolBar.snp_top).offset(7.5)
make.right.equalTo(self.sendButton.snp_left).offset(-2)
make.bottom.equalTo(self.toolBar.snp_bottom).offset(-8)
})
sendButton.snp_makeConstraints({ (make) -> Void in
make.right.equalTo(self.toolBar.snp_right)
make.bottom.equalTo(self.toolBar.snp_bottom).offset(-4.5)
})
是不是看起來簡潔多了?我們來解釋一下這段代碼:
每一個組件都有一個 snp_makeConstraints
的閉包方法,用來設置約束,textView.snp_makeConstraints
就是來設置textView的約束
閉包中make.left.equalTo(self.toolBar.snp_left).offset(8)
這行代碼可以用公式來表示:
也就是textView.left = self.toolBar.left + 8
,這樣一看就很直觀了,文字框的左側距輸入框左側8點。
make.top.equalTo(self.toolBar.snp_top).offset(7.5)
可以用公式
textView.top = self.toolBar.top +7.5
表示,剩下的代碼以此類推,如下圖所示:
sendButton的部分也是如此:
make.right.equalTo(self.toolBar.snp_right)
表示發送按鈕右側直接貼輸入框的右側,沒有位移make.bottom.equalTo(self.toolBar.snp_bottom).offset(-4.5)
發送按鈕底部距離輸入框底部4.5點這樣是不是讓autoLayout變得簡單很多了?后面的項目我們就一直使用它來進行autoLayout設置了!
現在沒有錯誤了,cmd+R運行一下,啊哦,為啥是空白!作者你騙人!( ⊙ o ⊙ )
= =好吧,我們還差一步,記得嗎,它要變成第一響應者才能彈出鍵盤哦,我們要重寫一個方法它才能生效!在視圖控制器類中增加以下方法:
override func canBecomeFirstResponder() -> Bool {
return true
}
告訴我們的系統我們自定義的輸入框可以成為第一響應者,我們也是有身份證的!
然后在運行一下,如果沒有錯誤,應該會有以下效果:
忽略黑洞洞的背景,因為我們還沒有添加內容。。。
但是你會發現一個問題,鍵盤怎么回來啊。。不管怎么點都沒有反應?。?/p>
好吧,下面我們來用一個巧妙的辦法來解決它。由于聊天頁面是一個UITableView,所以我們可以使用UITableViewContoller來替代我們的UIViewContoller,這樣我們的頁面中就默認有了一個UITableView,然后它有一個非常實用的屬性---keyboardDismissMode
,我們把它設置為.Interactive
也就是鍵盤的彈出和收回狀態可以根據你對tableView的拖拽進行改變,也就是你的手指拖到哪里你的鍵盤就到哪里,是不是很酷。
改變視圖控制器的類型:
class ChatViewController:UITableViewController,UITextViewDelegate {
....
....
....
}
在viewDidLoad里添加一行代碼來設置keyboardDismissMode
:
tableView.keyboardDismissMode = .Interactive
再次運行,你會發現黑洞洞的背景不見了,取而代之的是空白的TableView!而且鍵盤也實現了炫酷的效果!
文章本部分源代碼
好的,第三部分順利實現!第二部分是我們的重頭戲,內容較多,所以我把它放到教程的第二部分中。
第二部分教程已經出爐,歡迎圍觀!
swift實現一個與智能機器人聊天的app(二)