iOS開源一個簡單的訂餐app UI框架
前言
學(xué) Swift 也有一段時間了,做了一些小的 demo。一直想做個完整的項目,發(fā)現(xiàn)這邊學(xué)校的外賣訂餐也逐漸流行起來,不像中國有那么多強大的外賣軟件,美國也有,但不多,起碼中國人對那些軟件都不太熟知也不怎么用。打算專門針對午餐的外賣做個app,做了幾天,只做出個 UI,看上去很小的軟件,新手做起來感覺東西還是有點多。 Swift 如何與后端交互 之類的之后再慢慢學(xué)吧,有數(shù)據(jù)庫之類的我都挺熟悉,SQL 或者 MongoDB。
目錄
在這個 app 中,所有 UI 都是用代碼創(chuàng)建的,你可以在 100 Days of Swift 看到,我之前練習(xí)的時候都是用的 storyboard,但是到了10頁以上感覺 storyboard 就開始有點亂了,特別是那些 segue 的線牽得滿屏幕都是的時候。之后我就開始用 SnapKit 做 UI 了,雖然比起 CSS 來,還是有點不方便,但用起來感覺還行。下面我大概羅列了一些實現(xiàn)的基本功能:
引導(dǎo)頁
午餐菜單(tableView)
購物車,動畫
下拉刷新
自定義個人主頁 (collectionView)
Reminder 和 Setting 需要后臺,就用了 Alert 來簡單響應(yīng)了
全屏右滑退出
具體代碼請看我的 Github, 下面我就主要展示一下效果,稍微講一下實現(xiàn)過程,代碼中已有很多注釋。
引導(dǎo)頁

引導(dǎo)頁我是用 collectionView 做的,剛開始先判斷要不要進入引導(dǎo)頁,如果版本更新,則進入。collectionView 滑動方向設(shè)置為 .horizontal ,設(shè)置任意數(shù)量的頁數(shù)。添加一個啟動的 startButton ,設(shè)置前幾頁都為 startButton.isHidden = true ,最后一頁的時候顯示出來,再添加一個漸出的顯示動畫。
菜單和購物車

shoppingCart
菜單可以下拉刷新,本打算自定義下拉刷新,就像 ALin 的項目中那樣,但是好像有點問題,我就用了自帶的UIRefreshControl ,下拉的時候顯示刷新的時間,稍微調(diào)整了下時間的 format。代碼很簡單
self.refreshControl.attributedTitle = NSAttributedString(string: "Last updated on \(dateString)", attributes: attributes)
self.refreshControl.tintColor = UIColor.white
然后做了個購物車的動畫,將菜單里的圖片先放大后縮小“拋入”購物車,其實是沿著 UIBezierPath 走的一個路徑,這段動畫完了之后,在 animationDidStop() 里做購物車圖片的抖動,和顯示購買的物品數(shù)量,那個 countLabel 是個長寬都為 15 的在購物車圖片右上角的 UILabel() 。
先實現(xiàn)一個回調(diào)方法,當(dāng)點擊了cell上的購買按鈕后觸發(fā)
func menuListCell(_ cell: MenuListCell, foodImageView: UIImageView)
{
guard let indexPath = tableView.indexPath(for: cell) else { return }
// retrieve the current food model, add it to shopping cart model
let model = foodArray[indexPath.section][indexPath.row]
addFoodArray.append(model)
// recalculate the frame of imageView, start animation
var rect = tableView.rectForRow(at: indexPath)
rect.origin.y -= tableView.contentOffset.y
var headRect = foodImageView.frame
headRect.origin.y = rect.origin.y + headRect.origin.y - 64
startAnimation(headRect, foodImageView: foodImageView)
}
這是點擊購買之后的動畫實現(xiàn):
fileprivate func startAnimation(_ rect: CGRect, foodImageView: UIImageView)
{
if layer == nil {
layer = CALayer()
layer?.contents = foodImageView.layer.contents
layer?.contentsGravity = kCAGravityResizeAspectFill
layer?.bounds = rect
layer?.cornerRadius = layer!.bounds.height * 0.5
layer?.masksToBounds = true
layer?.position = CGPoint(x: foodImageView.center.x, y: rect.minY + 96)
KeyWindow.layer.addSublayer(layer!)
// animation path
path = UIBezierPath()
path!.move(to: layer!.position)
path!.addQuadCurve(to: CGPoint(x:SCREEN_WIDTH - 25, y: 35), controlPoint: CGPoint(x: SCREEN_WIDTH * 0.5, y: rect.origin.y - 80))
}
groupAnimation()
}
這是放大,縮小,拋入購物車的組動畫
// start group animation: throw, larger, smaller image
fileprivate func groupAnimation()
{
tableView.isUserInteractionEnabled = false
// move path
let animation = CAKeyframeAnimation(keyPath: "position")
animation.path = path!.cgPath
animation.rotationMode = kCAAnimationRotateAuto
// larger image
let bigAnimation = CABasicAnimation(keyPath: "transform.scale")
bigAnimation.duration = 0.5
bigAnimation.fromValue = 1
bigAnimation.toValue = 2
bigAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) // smaller image
let smallAnimation = CABasicAnimation(keyPath: "transform.scale")
smallAnimation.beginTime = 0.5
smallAnimation.duration = 1
smallAnimation.fromValue = 2
smallAnimation.toValue = 0.5
smallAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) // group animation
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [animation, bigAnimation, smallAnimation]
groupAnimation.duration = 1.5
groupAnimation.isRemovedOnCompletion = false
groupAnimation.fillMode = kCAFillModeForwards
groupAnimation.delegate = self
layer?.add(groupAnimation, forKey: "groupAnimation")
}
組動畫結(jié)束后的一些動畫效果。
// end image animation, start other animations
func animationDidStop(_ anim: CAAnimation, finished flag: Bool)
{ if anim == layer?.animation(forKey: "groupAnimation")
{ // start user interaction
tableView.isUserInteractionEnabled = true
// hide layer
layer?.removeAllAnimations()
layer?.removeFromSuperlayer()
layer = nil
// if user buy any food, show the count label
if self.addFoodArray.count > 0 {
addCountLabel.isHidden = false
} // show the count label
let goodCountAnimation = CATransition()
goodCountAnimation.duration = 0.25
addCountLabel.text = "\(self.addFoodArray.count)"
addCountLabel.layer.add(goodCountAnimation, forKey: nil) // shopping cart shaking
let cartAnimation = CABasicAnimation(keyPath: "transform.translation.y")
cartAnimation.duration = 0.25
cartAnimation.fromValue = -5
cartAnimation.toValue = 5
cartAnimation.autoreverses = true
cartButton.layer.add(cartAnimation, forKey: nil)
}
}
購物車?yán)锩婵梢栽黾樱瘻p少購買數(shù)量,總價跟著會動態(tài)變動。主要是有用到了兩個東西,一個是 selected 變量,一個是 reCalculateCount() 函數(shù)。根據(jù) selected 來決定最后的總價,如果有變動,則重新計算 (reCalculateCount)。
fileprivate func reCalculateCount()
{
for model in addFoodArray! {
if model.selected == true {
price += Float(model.count) * (model.vipPrice! as NSString).floatValue
}
}
// assign price
let attributeText = NSMutableAttributedString(string: "Subtotal: \(self.price)")
attributeText.setAttributes([NSForegroundColorAttributeName: UIColor.red], range: NSMakeRange(5, attributeText.length - 5))
totalPriceLabel.attributedText = attributeText
price = 0
tableView.reloadData()
}
沒有實現(xiàn) Pay() 功能。打算之后嘗試 Apple Pay ,之前用慣了支付寶,剛來美國的時候很難受,其實很多地方中國都已經(jīng)比美國好很多了。還好現(xiàn)在有了 Apple Pay ,還挺好用的。
自定義個人主頁

profile
本來打算做成簡書那樣,但是。。作為新手感覺還是有點難度。也是因為我這 app 里沒有必要實現(xiàn)那些,就沒仔細(xì)研究。
如前面提到的這頁用的 collectionView,兩個 section,一個是 UserCollectionViewCell , 下面是 HistoryCollectionViewCell 。 下面這個 section 像一個 table 的 section,有一個會自動懸浮的 header,這 header 用的是 ALin 大神的輪子, LevitateHeaderFlowLayout() ,當(dāng)然這個文件的 copyright 是用他的名字的。
class CollectionViewFlowLayout: LevitateHeaderFlowLayout {
override func prepare() {
super.prepare()
collectionView?.alwaysBounceVertical = true
scrollDirection = .vertical
minimumLineSpacing = 5
minimumInteritemSpacing = 0
}
}
這項目總體來說應(yīng)該算很小的,如果后端也實現(xiàn)了,也算一個蠻完整的小項目了吧。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- iOS App中UITableView左滑出現(xiàn)刪除按鈕及其cell的重用
- 詳解iOS App開發(fā)中改變UIButton內(nèi)部控件的基本方法
- iOS App開發(fā)中UISearchBar搜索欄組件的基本用法整理
- 詳解iOS App開發(fā)中UIViewController的loadView方法使用
- 詳解iOS App中UISwitch開關(guān)組件的基本創(chuàng)建及使用方法
- iOS App開發(fā)中修改UILabel默認(rèn)字體的方法
- iOS App中UIPickerView選擇欄控件的使用實例解析
- iOS App開發(fā)中的UISegmentedControl分段組件用法總結(jié)
- 詳解iOS App中UIPickerView滾動選擇欄的添加方法
- iOS App開發(fā)中使用及自定義UITableViewCell的教程
相關(guān)文章
關(guān)于iOS導(dǎo)航欄返回按鈕問題的解決方法
這篇文章主要為大家詳細(xì)介紹了關(guān)于iOS導(dǎo)航欄返回按鈕問題的解決方法,對iOS自定義backBarButtonItem的點擊事件進行介紹,感興趣的小伙伴們可以參考一下2016-05-05
iOS中3DTouch預(yù)覽導(dǎo)致TableView滑動卡頓問題解決的方法
這篇文章主要給大家介紹了關(guān)于iOS中3DTouch預(yù)覽導(dǎo)致TableView滑動卡頓問題解決的方法,文中通過示例代碼介紹的非常詳細(xì),對同樣遇到的朋友們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧。2018-03-03
關(guān)于iOS自適應(yīng)cell行高的那些事兒
這篇文章主要給大家介紹了關(guān)于iOS自適應(yīng)cell行高的那些事兒,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一看看吧2018-11-11
IOS實現(xiàn)選擇城市后跳轉(zhuǎn)Tabbar效果
這篇文章主要為大家詳細(xì)介紹了IOS實現(xiàn)選擇城市后跳轉(zhuǎn)Tabbar效果的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-07-07
iOS 10 和Xcode8 一起 創(chuàng)建 Siri 功能步驟詳解(OC寫的 )
這篇文章主要介紹了iOS 10 和Xcode8 一起 創(chuàng)建 Siri 功能(OC寫的 ),本文分步驟給大家介紹的非常詳細(xì),需要的朋友可以參考下2017-12-12

