不知不覺十一馬上到了,承諾給大家分享的Swift項目也該兌現(xiàn)了,本次項目為高仿小日子,廢話不多說,先看效果吧
![探店效果圖](http://ww3.sinaimg.cn/mw690/0068uRu1gw1ewa0wbgrztg307u0dx4qs.gif)
![探店詳情頁效果圖](http://ww3.sinaimg.cn/mw690/0068uRu1gw1ewa0xr60deg307u0dxu10.gif)
![附近地圖效果圖](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ewa0zdjs9bg307u0dx7wl.gif)
![體驗效果圖](http://ww1.sinaimg.cn/mw690/0068uRu1gw1ewa10dm5kfg307u0dxe83.gif)
![分類效果圖](http://ww1.sinaimg.cn/mw690/0068uRu1gw1ewa121334ig307u0dxx6s.gif)
![我的效果圖](http://ww3.sinaimg.cn/mw690/0068uRu1gw1ewa12zhy4mg307u0dx4qr.gif)
![搜索效果圖](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ew9zyhxjg2g307r0dub29.gif)
![搖一搖效果圖](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ewa977vlamg307u0dxe81.gif)
更多效果請用Xcode7.0正式版運(yùn)行程序查看
此項目相對來說比較簡單,之前用Swift1.2編寫的,9月18號,蘋果發(fā)布了Xcdoe7.0正式版,小熊也將代碼更新到了Swift2.0,由于Swift語言還不穩(wěn)定,每個版本都會出現(xiàn)語法修改,本項目用最新的Xcode7正式版編寫,建議使用Xcode7正式版運(yùn)行工程,項目的接口依然有加密,抱著學(xué)習(xí)的態(tài)度,小熊截取了網(wǎng)絡(luò)請求返回數(shù)據(jù),并且將數(shù)據(jù)寫入到了本地,所以讀者用到的數(shù)據(jù)都是固定的
本來想挑一個復(fù)雜點的項目分享給大家,考慮到公司的項目要在十一前上線,時間比較緊,以及自己對Swift語言還處于摸索階段,經(jīng)常也是連蒙加猜的,很多寫法還是沿用OC的套路,不過相信對于大家學(xué)習(xí)Swift語言還是有一定幫助的.很多時候,小熊都是被一個很簡單的語法卡住很久,比如如何動態(tài)實例化AnyClass對象,還有升級到2.0后,通過NSStringFromClass:方法創(chuàng)建對象是需要追加命名空間的前綴,我記憶很深刻...
此次寫代碼的過程中吸取了讀者的提議,用的源代碼管理工具是git,大家可以在項目的歷史版本回退查看項目的從無到有是如何一步一步完善的,由于白天上班,晚上寫這個項目,所以中間博客沒有怎么更新,讀者也可以從代碼提交時間看出...都是半夜1 . 2點左右
在學(xué)習(xí)Swift語言中,自己也斷斷續(xù)續(xù)的總結(jié)了一些OC和Swift語法的區(qū)別,以及Swift于OC中相同方法的不用寫法,我也會在后續(xù)時間發(fā)布到博客里,讓大家避免不必要的麻煩,請持續(xù)關(guān)注小熊的博客
下面來介紹此項目的每個模塊的思路,這里就按照程序運(yùn)行展示的頁面的順序逐一與大家分析吧
引導(dǎo)頁(新特性頁面)
-
引導(dǎo)頁只在用戶第一次運(yùn)行程序,或者APP升級后第一次運(yùn)行程序時候出現(xiàn),為了是提示用戶APP的新功能以及改變
如下圖所展示的效果
引導(dǎo)頁 目前比較主流的方法是使用UICollectionview來實現(xiàn)引導(dǎo)頁
可以直接復(fù)用
,如果只是單純的圖片和簡單的動畫建議使用UICollectionview,如果有比較復(fù)雜的動畫,也可以用ScrollView來實現(xiàn),根據(jù)項目的不同需求來選擇,這里的引導(dǎo)頁只有一頁,我就直接用的View在程序啟動成功的方法中,首先判斷用戶是否是第一次運(yùn)行當(dāng)前版本的APP,我的做法是用版本號來判斷,首先在info中拿出當(dāng)前程序的版本號,在從UserDefaults取出上次用戶運(yùn)行程序的版本號對比,如果相等,說明沒有新版本,直接進(jìn)入,如果不相等則顯示導(dǎo)引頁,并且將當(dāng)前版本寫入UserDefaults中,以便下次用戶運(yùn)行APP判斷.具體代碼如下,返回的控制器作為keyWindow的rootViewController,如果是引導(dǎo)頁,并且用戶點擊了體驗按鈕,可以發(fā)出通知,將KeyWindow的rootViewController切換即可
privete func showLeadpage() -> UIViewController {
let versionStr = "CFBundleShortVersionString"
let cureentVersion = NSBundle.mainBundle().infoDictionary![versionStr] as! String
let oldVersion = (NSUserDefaults.standardUserDefaults().objectForKey(versionStr) as? String) ?? ""
if cureentVersion.compare(oldVersion) == NSComparisonResult.OrderedDescending {
NSUserDefaults.standardUserDefaults().setObject(cureentVersion, forKey: versionStr)
NSUserDefaults.standardUserDefaults().synchronize()
return LeadpageViewController()
}
UITabbarController(KeyWindow.rootViewController)
- 這里小熊自己定義的MainTabBarController繼承至UITabBarController,里面裝了四個MainNavigationController
繼承UINavigationController
作為子控制器 - MainNavigationController
繼承UINavigationController
,重寫了pushViewController方法,方便統(tǒng)一管理返回按鈕和每次Push出新的控制器,自動隱藏底部的TabBar,具體代碼如下
override func pushViewController(viewController: UIViewController, animated: Bool) {
if self.childViewControllers.count > 0 {
let vc = self.childViewControllers[0]
if self.childViewControllers.count == 1 {
backBtn.setTitle(vc.tabBarItem.title!, forState: .Normal)
} else {
backBtn.setTitle("返回", forState: .Normal)
}
viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBtn)
viewController.hidesBottomBarWhenPushed = true
}
super.pushViewController(viewController, animated: animated)
}
左上角的城市
- 由于探店, 體驗, 分類都有城市選擇按鈕,并且一個改變,其余的也都會改變,我的做法是提供一個父類,MainViewController
繼承至UIViewController
,設(shè)置navigationItem.leftBarButtonItem為自定義的按鈕,并且在viewDidLoad:方法中,添加通知,監(jiān)聽city的改變,一旦監(jiān)聽到當(dāng)前城市發(fā)生改變的通知后,對應(yīng)的控制器就可以執(zhí)行對應(yīng)的操作,需要注意的是
每次要將改變后的城市寫入到本地持久化存儲,以便程序被關(guān)閉后再次運(yùn)行時,可以保留上次用戶所選擇的城市 - 選擇城市的控制器是CityViewController
如下圖
,城市的展示小熊用的UICollectionview來展示的,需要注意每次ViewController彈出后,用戶上一次選擇的城市都會自動進(jìn)入選中狀態(tài),具體實現(xiàn)是拿出上一次用戶選擇的城市,遍歷城市列表取出所屬的indexPath,然后執(zhí)行下面方法
let lastSelectedCityIndexPaht = selectedCurrentCity()
collView.selectItemAtIndexPath(lastSelectedCityIndexPaht, animated: true, scrollPosition: UICollectionViewScrollPosition.None)
![城市選擇控制器](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ew9ztn1q17g307r0du7pm.gif)
- 當(dāng)用戶再次選擇城市后,將城市寫入到本地保存,并且發(fā)出城市改變的通知,通知監(jiān)聽者做出相應(yīng)的操作
探店如下圖所示
![探店效果圖](http://ww3.sinaimg.cn/mw690/0068uRu1gw1ew9ztcztatg307r0dub29.gif)
導(dǎo)航條上的美天和美輯是將navigationItem.titleView 設(shè)置為自定義的DoubleTextView來實現(xiàn),內(nèi)部封裝好功能,并且通過設(shè)置代理將點擊事件傳遞給控制器,順便提一嘴,Swift中的代理和OC中的一樣,也是采用軟引用即:
weak var delegate: <Delegate>?
,提供一個方法便于在scrollView的offsetX發(fā)生改變時更新內(nèi)部控件狀態(tài)具體實現(xiàn)請參考項目中的代碼
-
在view的最底層添加一個scrollView,設(shè)置scorllView的contentSize為屏幕的寬度的2倍,在scrollView上添加倆個TableView,分別是美天的TableView和美輯的TabelView,注意觀察,美天tableViewCell有一種cell的樣式于美輯的樣式是一樣的,所以這里只用了兩種cell,參考下圖,這里是根據(jù)服務(wù)器返回數(shù)據(jù)來判斷加載哪一種cell,美天的tableView采用的是樣式是Group樣式,每一組有一個或者多個cell
EventCell樣式效果圖
ThemeCell樣式效果圖 在TableView的代理方法中,根據(jù)服務(wù)器返回的數(shù)據(jù)創(chuàng)建對應(yīng)的cell,喜歡專研的朋友可以查看項目中CustomData文件中的events.json文件查看規(guī)律
這里提一下Swift的閉包方法中,需要像OC中一樣創(chuàng)建一個weak的指針weak var tmpSelf = self,在閉包方法中調(diào)用tmpSelf,直接調(diào)用self會引起循環(huán)引用,照成內(nèi)存泄露,控制器無法被銷毀問題
-
點擊EventCell彈出的詳情頁我著重講一下,先看效果圖
美天詳情效果圖 頂部的導(dǎo)航條是自定義的view,在EventViewController的viewWillAppaer方法中,將系統(tǒng)的導(dǎo)航條隱藏掉,添加定義的view作為導(dǎo)航條,按鈕也是如此,根據(jù)scrollView的偏移量計算透明度,圖片的拉伸和按鈕的圖片改變,由于有倆個scrollView,有些效果需要判斷不同scrollView來執(zhí)行,需要注意的是適當(dāng)添加標(biāo)記來防止重復(fù)判斷,消耗內(nèi)存
店發(fā)現(xiàn)和店詳情掌握之前提的導(dǎo)航條titelView也可以輕松搞定,位置也是根據(jù)scrollView的Y軸的偏移量來計算,代碼并不復(fù)雜,具體代碼如下
extension EventViewController: UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView) {
// 解決彈出新的控制器后返回后contentSize自動還原的問題
if loadFinishScrollHeihgt > webView.scrollView.contentSize.height && scrollView === webView.scrollView {
webView.scrollView.contentSize.height = loadFinishScrollHeihgt
}
let offsetY: CGFloat = scrollView.contentOffset.y
// 判斷頂部自定義導(dǎo)航條的透明度,以及圖片的切換
customNav.alpha = 1 + (offsetY + NavigationH + EventViewController_ShopView_Height) / scrollShowNavH
if offsetY + EventViewController_ShopView_Height >= -NavigationH && showBlackImage == false {
backBtn.setImage(UIImage(named: "back_1"), forState: .Normal)
likeBtn.setImage(UIImage(named: "collect_1"), forState: .Normal)
sharedBtn.setImage(UIImage(named: "share_1"), forState: .Normal)
showBlackImage = true
} else if offsetY < -NavigationH - EventViewController_ShopView_Height && showBlackImage == true {
backBtn.setImage(UIImage(named: "back_0"), forState: .Normal)
likeBtn.setImage(UIImage(named: "collect_0"), forState: .Normal)
sharedBtn.setImage(UIImage(named: "share_0"), forState: .Normal)
showBlackImage = false
}
// 頂部imageView的跟隨動畫
if offsetY <= -DetailViewController_TopImageView_Height - EventViewController_ShopView_Height {
topImageView.frame.origin.y = 0
topImageView.frame.size.height = -offsetY - EventViewController_ShopView_Height
topImageView.frame.size.width = AppWidth - offsetY - DetailViewController_TopImageView_Height
topImageView.frame.origin.x = (0 + DetailViewController_TopImageView_Height + offsetY) * 0.5
} else {
topImageView.frame.origin.y = -offsetY - DetailViewController_TopImageView_Height - EventViewController_ShopView_Height
}
// 處理shopView
if offsetY >= -(EventViewController_ShopView_Height + NavigationH) {
shopView.frame = CGRect(x: 0, y: NavigationH, width: AppWidth, height: EventViewController_ShopView_Height)
} else {
shopView.frame = CGRect(x: 0, y: CGRectGetMaxY(topImageView.frame), width: AppWidth, height: EventViewController_ShopView_Height)
}
// 記錄scrollView最后的偏移量,用于切換scrollView時同步倆個scrollView的偏移值
lastOffsetY = offsetY
}
}
-
店發(fā)現(xiàn) 這里相對來說有點麻煩,這里服務(wù)器返回的是好長的一串htmlString,由于沒有css的布局文件,直接加載htmlStr的話圖片是超級的大,有的像素達(dá)到4480*3000,直接用webView.loadHTMLString:的方法很不現(xiàn)實,這里我放一段服務(wù)器返回的字符串給讀者看一下
如下圖
html返回的字符串 由于沒有css的布局文件,只能靠自己來約束圖片的大小,我采用的方法是通過正則語句過濾出所有圖片的寬和高,然后按照屏幕的寬度等比例計算圖片的大小,在將修改過的寬和高替換插入到原有的htmlStr中,觀察服務(wù)器返回的htmlStr是沒有title和tag的,也就意味這展示的內(nèi)容沒有標(biāo)題和標(biāo)簽,所以再動態(tài)的將title以及tag的標(biāo)簽插入到字符串中
插入代碼如下
if model?.title != nil {
titleStr = String(format: "<p style='font-size:20px;'> %@</p>", model!.title!)
}
if model?.tag != nil {
titleStr = titleStr?.stringByAppendingFormat("<p style='font-size:13px; color: gray';>%@</p>", model!.tag!)
}
- 再加載修改過圖片寬高的htmlStr,然后webViewDidFinishLoad的方法中,通過JS代碼將內(nèi)容的背景色修改,此種方法瑕疵很多,代碼如下
webView.stringByEvaluatingJavaScriptFromString("document.getElementsByTagName('body')[0].style.background='#F5F5F5';")
對webView圖片的處理,小熊感覺還有一個更好的思路可以嘗試,不過在項目中沒有實現(xiàn)成功,這里我覺得可以動態(tài)的將所有的的htmlStr中image都攔截掉,不讓webView自己加載圖片,并且通過條件過濾保留圖片的url地址,動態(tài)的計算出圖片的位置和大小,用本地加載圖片的方法加載圖片,放到對應(yīng)webView.scrollView的位置,這樣就可以實現(xiàn)緩存,以及點擊等事件,不過需要于js端的配合,這個以后我一定會再嘗試的,可行的話我會將demo分享給大家
在webView的最底部,也會根據(jù)服務(wù)器返回的數(shù)據(jù)動態(tài)的加入猜你喜歡的cell,這里只需要在webView加載完畢后,確認(rèn)webView.scrollView.contentSize.height后面添加對應(yīng)的moreView即可!
需要注意的是,添加內(nèi)容后,也要相應(yīng)的增加webView.scrollView.height的高度用來顯示新添加的控件
附近(效果如下圖所示)
![附近地圖效果圖](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ew9zzrsv71g307r0dub2b.gif)
- 在程序啟動成功的方法中,首先會獲取用戶授權(quán)使用定位功能,這里我封裝了一個管理用戶位置的單例,當(dāng)用戶授權(quán)App可以使用定位后,獲取用戶當(dāng)前的經(jīng)緯度并且將用戶位置的經(jīng)緯度保存,當(dāng)用戶點擊附近按鈕彈出控制器時,發(fā)送網(wǎng)絡(luò)請求給服務(wù)器,服務(wù)器通過用戶當(dāng)前的經(jīng)緯度返回附近店鋪的信息,由于沒有數(shù)據(jù),所以每次返回的都是小熊寫在本地的數(shù)據(jù),解析對應(yīng)的數(shù)據(jù)加載到tableView顯示,通過用戶的位置以及店鋪的位置可以計算出距離給label設(shè)置用戶當(dāng)前距離店鋪的距離
KM
- 翻轉(zhuǎn)動畫,根據(jù)右上角按鈕的狀態(tài)使用下面方法完成翻轉(zhuǎn)動畫
if sender.selected {
UIView.transitionFromView(nearTableView, toView: mapView, duration: 1.0, options: UIViewAnimationOptions.TransitionFlipFromLeft, completion: nil)
} else {
UIView.transitionFromView(mapView, toView: nearTableView, duration: 1.0, options: UIViewAnimationOptions.TransitionFlipFromRight, completion: nil)
}
- mapView中,有一個UICollectionview,一個定位到當(dāng)前用戶位置的按鈕,以及自定義的大頭針若干,判斷大頭針的選中狀態(tài)切換大頭針的圖片,根據(jù)選中的shopCell切換選中大頭針等,都是一些計算性的代碼,具體代碼參考
WNXMapView.swift
文件,點擊shopCell推出對應(yīng)的控制器即可
體驗
- 體驗控制器值得一提的是TableViewCell的高度計算方法采用了iOS8.0的新方法,通過約束cell底部來自動計算cell的高度,在xib中約束好cell底部后,在初始化TableView時,通過下面?zhèn)z句代碼就可以實現(xiàn)cell自動計算高度
// 估算cell的高度
tableV.estimatedRowHeight = 200
// 設(shè)置tableView的自動布局樣式
tableV.rowHeight = UITableViewAutomaticDimension
- 這個方法局限性比較大,只可以在確定cell底部約束對象時才可以采用,根據(jù)需求情況有時使用會比較方便
必須iOS8.0以上才可以
體驗詳情控制器效果如下圖所示
- 可以看出體驗詳情控制器與探店詳情控制器大同小異,不同的是底部動態(tài)添加的控件.
- 報名控制器需要注意鍵盤對TextField的遮蓋,監(jiān)聽鍵盤將要改變Frame的通知,設(shè)置scrollView的偏移Y軸的偏移值,保證鍵盤無法遮蓋住輸入框,網(wǎng)網(wǎng)項目中最耗時的就是這些細(xì)節(jié)性的動畫,既考驗開發(fā)人員的細(xì)心,又考驗開發(fā)人員的耐心
- 當(dāng)用戶輸入好報名信息并且點擊提交后,將報名信息通過sql語句插入到本地數(shù)據(jù)庫,為了給后面我的訂單中使用
搜索控制器(效果圖如下)
![搜索控制器](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ew9zyhxjg2g307r0dub29.gif)
- 這里有個小小的動畫,是根據(jù)鍵盤監(jiān)聽鍵盤Frame改變發(fā)出的通知來做出相應(yīng)的動畫,值得提醒大家的是:通過真機(jī)調(diào)試發(fā)現(xiàn),當(dāng)用戶手機(jī)安裝三方的鍵盤時
(搜狗輸入法...)
,鍵盤彈出和隱藏的通知會連續(xù)發(fā)出多次,需要加上標(biāo)記來判斷即可,模擬器中我還沒發(fā)現(xiàn)這種情況,望大家注意
我的
用戶頭像View
首先利用封裝的用戶賬號管理工具判斷當(dāng)前用戶是否登陸,如果未登錄,則推出登陸界面,當(dāng)用戶登陸或者注冊后,將用戶的賬號,以及加密過的密碼發(fā)送給服務(wù)器,以及在本地備份,便于程序關(guān)閉后,下次運(yùn)行程序時,用戶不需要再次登陸.
如果用戶已登錄并且點擊iconView后,打開UIImagePickerController,根據(jù)用戶選擇的是打開相冊還是相機(jī)來設(shè)置UIImagePickerController對象的sourceType.當(dāng)用戶點擊相機(jī)時,需要先判斷用戶當(dāng)前攝像頭是否可用,
注意模擬器沒有攝像頭,需要在真機(jī)調(diào)試才可以打開攝像頭
,設(shè)置照片為可編輯模式,這樣用戶選擇的圖片將會是正方形,方便頭像的圓形的裁剪這里有一個地方值得注意,就是隨著相機(jī)像素的提高,實際用戶選擇的圖片都是很大的,有的高達(dá)5.6M,如果直接使用用戶選著的圖片,非常消耗內(nèi)存,并且也用不到這么高像素的圖片,可以當(dāng)用戶選著好圖片后,在UIImagePickerController對應(yīng)的代理方法中,先將圖片進(jìn)行重新繪制為需要的大小,在設(shè)置給iconView
具體代碼如下所示
/// MARK: 攝像機(jī)和相冊的操作和代理方法
extension MeViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
/// 打開照相功能
private func openCamera() {
if UIImagePickerController.isSourceTypeAvailable(.Camera) {
pickVC.sourceType = .Camera
self.presentViewController(pickVC, animated: true, completion: nil)
} else {
SVProgressHUD.showErrorWithStatus("模擬器沒有攝像頭,請鏈接真機(jī)調(diào)試", maskType: SVProgressHUDMaskType.Black)
}
}
/// 打開相冊
private func openUserPhotoLibrary() {
pickVC.sourceType = .PhotoLibrary
pickVC.allowsEditing = true
presentViewController(pickVC, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
// 對用戶選著的圖片進(jìn)行質(zhì)量壓縮,上傳服務(wù)器,本地持久化存儲
if let typeStr = info[UIImagePickerControllerMediaType] as? String {
if typeStr == "public.image" {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
var data: NSData?
let smallImage = UIImage.imageClipToNewImage(image, newSize: iconView!.iconButton.size)
if UIImagePNGRepresentation(smallImage) == nil {
data = UIImageJPEGRepresentation(smallImage, 0.8)
} else {
data = UIImagePNGRepresentation(smallImage)
}
if data != nil {
do {
// TODO: 將頭像的data傳入服務(wù)器
// 本地也保留一份data數(shù)據(jù)
try NSFileManager.defaultManager().createDirectoryAtPath(theme.cachesPath, withIntermediateDirectories: true, attributes: nil)
} catch _ {
}
NSFileManager.defaultManager().createFileAtPath(SD_UserIconData_Path, contents: data, attributes: nil)
iconView!.iconButton.setImage(UIImage(data: NSData(contentsOfFile: SD_UserIconData_Path)!)!.imageClipOvalImage(), forState: .Normal)
} else {
SVProgressHUD.showErrorWithStatus("照片保存失敗", maskType: SVProgressHUDMaskType.Black)
}
}
}
} else {
SVProgressHUD.showErrorWithStatus("圖片無法獲取", maskType: SVProgressHUDMaskType.Black)
}
picker.dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
pickVC.dismissViewControllerAnimated(true, completion: nil)
}
}
搖一搖
![搖一搖效果圖](http://ww2.sinaimg.cn/mw690/0068uRu1gw1ewa977vlamg307u0dxe81.gif)
- 搖一搖使用的是蘋果提供好的方法override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?),每當(dāng)用戶搖晃手機(jī)時,系統(tǒng)就會自動調(diào)用此方法,在方法內(nèi)部做出相應(yīng)的動畫即可
關(guān)鍵代碼就這下面這幾句,如果是使用模擬器可以點擊窗口上**Hardware -> Shake Gesture**來進(jìn)行模擬調(diào)試
override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?) {
tableView!.hidden = true
let animateDuration: NSTimeInterval = 0.3
let offsetY: CGFloat = 50
UIView.animateWithDuration(animateDuration, animations: { () -> Void in
self.yaoImageView1.transform = CGAffineTransformMakeTranslation(0, -offsetY)
self.yaoImageView2.transform = CGAffineTransformMakeTranslation(0, offsetY)
}) { (finish) -> Void in
let popTime = dispatch_time(DISPATCH_TIME_NOW,Int64(0.5 * Double(NSEC_PER_SEC)))
dispatch_after(popTime, dispatch_get_main_queue(), { () -> Void in
UIView.animateWithDuration(animateDuration, animations: { () -> Void in
self.yaoImageView1.transform = CGAffineTransformIdentity
self.yaoImageView2.transform = CGAffineTransformIdentity
}, completion: { (finish) -> Void in
self.loadShakeData()
// 音效
AudioServicesPlayAlertSound(self.soundID!)
})
})
}
清理緩存
- 這里我封裝了一個工具類:FileTool,通過類方法可以調(diào)用查看指定路徑文件夾的大小
FileTool.folderSize(path: String)
,以及異步刪除指路徑下的全部文件夾FileTool.cleanFolder(path: String, complete: () -> ())
,complete為刪除完成后的回調(diào)
三方分享
- 這里我封裝了一個分享工具類ShareTool,集成了新浪SSO,微信SSO認(rèn)證,以及新浪OAuth認(rèn)證.采用的是友盟分享SDK,以及自定義的分享界面,需要注意的是由于微信沒有OAuth認(rèn)證,所以只有在設(shè)備安裝了微信時才可以分享(
插上你的真機(jī)分享點擊分享試一試
),模擬器中只可以使用新浪微博的分享. - 如果想要將新浪分享的來自xx和圖片修改為自己應(yīng)用的圖標(biāo),可以在新浪的開發(fā)者平臺注冊成為開發(fā)者,添加應(yīng)用并且上線,通過審核,在友盟網(wǎng)站我的產(chǎn)品中將設(shè)置主題修改相應(yīng)的屬性即可.
- 在iOS9.0后,需要設(shè)置白名單以及回調(diào)的白名單才可以完成分享后的回調(diào)
關(guān)于項目的介紹基本就這么多了,更多的細(xì)節(jié)和內(nèi)容直接看代碼來的更快捷一些,對于Swift小熊也是又愛又恨,相信隨著版本的不斷更新,Swift語言也會越來越趨于穩(wěn)定,Xcode對Swift的支持也會越來越好的,總算對自己的承諾有了一個小小的交代,如果有小熊的項目有幫助到大家,請到我的GitHub點個星,項目中會有很多不足之處,歡迎到我的博客留言與交流,小熊希望與大家共同進(jìn)步_~,提前祝大家十一快樂
直接打開運(yùn)行工程
![打開工作組運(yùn)行工程](http://ww4.sinaimg.cn/mw690/0068uRu1gw1ewa9bfaipcj30au0c4t9p.jpg)