訂飲料App
幫助揪團訂飲料的總召統計份量甜度冰塊
這次做一個可以方便統計飲料清單的app,方便不想手寫或打字記錄飲料清單的公司點飲料總召。總召可以傳手機給同事們,或本人直接代替幫忙點選飲料的內容,而在點選過程中選取內容就會自動列在畫面中間 (待確認訂單),總召也可以隨時手動修改內容。在確認無誤後按確認訂單鈕,訂單就會以條列式列在下方變成不可修改的狀態 (已確認訂單)。
功能設計
UISegmentedControl
- 選擇飲料的分量,甜度、冰塊
- 點選加糖和冰的區塊時,顯示可以調整甜度、冰塊細節的Slider
UISlider / UIButton
- Slider的數值增減以UIButton控制 (Slider的Thumb 維持不作用),
甜度的數值分為無糖(0)、微糖(0.25)、半糖(0.5)、少糖(0.75)、全糖(1); 冰塊的數值分為完全去冰(0)、去冰(0.2)、微冰(0.5)、少冰(0.8)、正常冰(1)
UITextField / UIButton
- 在兩個任一TextField裡輸入文字後,點選確認訂單讓文字自動跑進UILabel中以顯示逐筆訂單,UILabel中訂單無法手動更改
- 點選全部清空按鈕以清空Label和TextField內的文字
SegmentedControl被點選時,同步顯示文字於textField中
當點選份量、甜度、冰塊時,對應的內容可以同時記錄在下方欄位,方便隨時做確認。
var size = ["小杯・","中杯・","大杯・"]
var sizeIndex: Int?var sugar = ["無糖","加糖"]
var sugarIndex: Int?var sugarDetails = ["","(微糖)","(半糖)","(少糖)","(全糖)"]
var sDIndex: Int?
var ice = ["・冰","・溫","・熱"]
var iceIndex: Int?
var iceDetails = ["(完全去冰)","(去冰)","(微冰)","(少冰)","(正常冰)"]
var iDIndex: Int?func setIndex(){
var content = ""
//如果點選了份量segmentedControl
if sizeIndex != nil{
content = content + size[sizeIndex!]
print("sizeIndex",content)
} //如果點選了甜度segmentedControl
if sugarIndex != nil{
content += sugar[sugarIndex!]
} //如果點選了甜度細節的button
if sDIndex != nil{
if sugarSegmentedControl.selectedSegmentIndex != 0{
content = content + sugarDetails[sDIndex!]
}
} //如果點選了冰塊的segmentedControl
if iceIndex != nil{
content = content + ice[iceIndex!]
} //如果點選了冰塊細節的button
if iDIndex != nil{
if iceSegmentedControl.selectedSegmentIndex == 0{
content = content + iceDetails[iDIndex!]
}
}
selectedItemTextField.text = content
}
【程式說明】
先設定變數儲存飲料的份量(size)、甜度有無(sugar)&甜度細節(sugarDetails)、冰溫熱(ice)&冰塊細節(iceDetails)的array; 變數Index用來之後儲存使用者點選到的內容。
→ 因為份量、甜度有無、冰溫熱可以是未點選狀態 (nil),所以將Index宣告成Optional。另外sugarDetails[0]本來設定為”無糖”,但為了不跟甜度SegmentedControl的無糖重複,所以為了配合同樣是五個elements的iceDetails,就維持空字串了。
接著自訂一個func將使用者選擇的甜度冰塊,儲存待確認訂單在contents (空字串)裡,並同步以文字顯現在selectedItemTextField中。
→ 將份量、甜度有無&甜度細節、冰溫熱&冰塊細節的屬性全部包在func中是因爲之後不論觸發任一元件,程式都要重複將前面點選過的屬性文字再顯示在textField中一次。舉例來說app啟動後,使用者與元件互動時與程式是這樣跑的:
1. 總召先選擇中杯 → 中
的segment被點選,textField同時顯示“中杯”
2. 總召再選加糖 →加糖
的segment被點選,textField顯示“中杯・加糖(微糖)”
,並且下方會同時跑出甜度細節的slider、button、Label (因為呼叫了sugarLabelchange())
因slider已預設好了“微糖”的初始值,所以textField中再顯示了一次“中杯・加糖(微糖)”
4. 總召最後發現第一個份量選錯,應該選大杯的→
textField中修改內容後收鍵盤
當點選份量、甜度、冰塊時,想要手動修改內容時就可以在TextField裡叫出鍵盤,但修改完畢要收鍵盤時要如何設定呢?
// 點空白處收鍵盤
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
// 點return鍵收鍵盤
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder();
return true
}
其他詳細說明可以參考下面的文章
用Button調整甜度冰塊細節,細節同步以文字顯示在Label和textField中
設計邏輯上不能出現以下三種情況:
- 甜度segmentedControl選擇
無糖
後,Label和textField中顯示無糖以外的甜度。例如Label未自動顯示無糖、textfield出現無糖(微糖)、無糖(半糖)、無糖(全糖)
為了解決第一點,在slider的value為0
的條件下將if sDIndex != nil 的區塊
拿掉就OK了。意思是指飲料是無糖時,textField中的”無糖”
文字顯示來源只會是甜度SegmentedControl。
//當甜度slider數值為0(代表無糖),Label也要顯示無糖 ; 甜度segmentedControl的sugarIndex數值須為0(代表無糖),sugar[0]存入content後顯示在textField裡func sugarLabelchange(){
if sugarSlider.value == 0{
setSugarSliderDetails(text: " 無糖 ", minTrackTintColor: sugarFifthColor, thumbTintColor: sugarFifthColor)
var content = ""
if sizeIndex != nil{
content = content + size[sizeIndex!]
print("sugarS0-size",content)
}
sugarIndex = 0
if sugarIndex != nil{
content += sugar[sugarIndex!]
print("sugarS0-sugar",content)
}
if iceIndex != nil{
content = content + ice[iceIndex!]
print("sugarS0-ice",content)
}
if iDIndex != nil{
if iceSegmentedControl.selectedSegmentIndex == 0{
content = content + iceDetails[iDIndex!]
print("sugarS0-iceD",content)
}
}
selectedItemTextField.text = content}
}
2. 甜度segmentedControl選擇加糖
後,Label和textField還是顯示無糖,
沒有自動顯示加糖、textfield出現加糖(無糖)
為了解決第二點,則在點選加糖segment後,強制將slider的value變成微糖(0.25)
作為預設值,Label顯示微糖,Textfield顯示“加糖(微糖)”
。
3. 冰塊segmentedControl選擇溫或熱後,還能用slider選擇冰塊細節,並且textField出現(完全去冰)、(去冰)、(微冰)、(少冰)、(正常)
而解決第三點的辦法就是在溫、熱被點選時仍隱藏冰塊slider,並且拿掉if iDIndex != nil 的區塊
,讓冰塊細節不會出現在textField中
@IBAction func iceSegmentSelected(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
iceHidden(change: false)
iceValue = 0.5
iceSlider.value = Float(iceValue)
iceLabelChange()
iceIndex = 0
iDIndex = 2
setIndex()
//點選溫
}else if sender.selectedSegmentIndex == 1{
iceHidden(change: true)
iceSlider.value = Float(iceValue)
iceLabelChange()
var content = ""
if sizeIndex != nil{
content = content + size[sizeIndex!]
print("ice1-size",content)
}
if sugarIndex != nil{
content += sugar[sugarIndex!]
print("ice1-sugar",content)
}
if sDIndex != nil{
content += sugarDetails[sDIndex!]
print("ice1-sugarD",content)
}
iceIndex = 1
if iceIndex != nil{
content = content + ice[iceIndex!]
print("ice1-ice",content)
}
selectedItemTextField.text = content //點選熱
}else if sender.selectedSegmentIndex == 2{
iceHidden(change: true)
iceSlider.value = Float(iceValue)
iceLabelChange()
var content = ""
if sizeIndex != nil{
content = content + size[sizeIndex!]
print("ice2-size",content)
}
if sugarIndex != nil{
content += sugar[sugarIndex!]
print("ice2-sugar",content)
}
if sDIndex != nil{
content += sugarDetails[sDIndex!]
print("ice2-sugarD",content)
}
iceIndex = 2
if iceIndex != nil{
content = content + ice[iceIndex!]
print("ice2-ice",content)
}
selectedItemTextField.text = content
}
}
讓Label外觀為圓角,Label大小隨著文字改變
func updateSugarViewSize(){
sugarLabel.sizeToFit()
sugarView.layer.cornerRadius = 3
sugarView.frame.size = sugarLabel.frame.size
}
func updateIceViewSize(){
iceLabel.sizeToFit()
iceView.layer.cornerRadius = 3
iceView.frame.size = iceLabel.frame.size
}
Label無法設定圓角但View可以,所以將View疊在Label上,圓角設定在View上; Label的大小設定sizeToFit(),讓尺寸會跟著文字內容變動。最後再將View的大小配合Label大小改變。
按下確認訂單鈕後,待確認訂單變為已確認訂單
當份量甜度冰塊確定不再更改時,按確定訂單
按鈕就能變為已確認訂單顯示在下方欄位中。
@IBOutlet weak var memoTextField: UITextField!
@IBOutlet weak var selectedItemTextField: UITextField!
@IBOutlet weak var confirmButton: UIButton!
@IBOutlet weak var contentLabel: UILabel!var confirmedContent = ""
var num = 1
@IBAction func confirmButtonPressed(_ sender: UIButton) {
contentLabel.textColor = UIColor.darkGray
contentLabel.font = UIFont.systemFont(ofSize: 14)
confirmedContent.append("\(num). ")
confirmedContent.append(selectedItemTextField.text!)
confirmedContent.append("\t")
confirmedContent.append(memoTextField.text!)
confirmedContent.append("\n")
contentLabel.text = confirmedContent
selectedItemTextField.text = ""
memoTextField.text = ""
num = num + 1
print(confirmedContent)
print("sugar: \(sugarValue),ice: \(iceValue)") }
【UILabel設定】
contentLabel
的文字顏色和大小設定如下,
contentLabel.textColor = UIColor.darkGray
contentLabel.font = UIFont.systemFont(ofSize: 14)
為了讓contentLabel
能夠容進多一點的文字,要將Text設定為Attributed,Lines設為 0 (代表不限制列數的最大上限),設定AutoShrink的Minimum Font Size或Minimum Font Scale 0.5 (當文字要超出範圍時縮小字體,字體最小為14*0.5)。而設定Minimum Font Scale 0.5的結果,Label從原本只能容納8列變成可以容納17列。
【程式說明】
宣告一個變數confirmedContent
儲存待確認訂單,和一個變數num
記錄已確認的訂單編號。因為訂單編號會逐漸遞增,所以宣告在confirmButtonPressed
的func外面。
利用append的方式將待確認訂單(selectedItemTextField)、備註欄(memoTextField)的文字和編號添加進confirmedContent
中,將confirmedContent
的內容設為contentLabel
的文字就完成了。
為了做出已確認訂單逐筆累積在contentLabel
裡,所以
最後還需要將待確認訂單(selectedItemTextField)和備註欄文字(memoTextField)指定為空字串讓它重新歸零、訂單編號+1,讓下一次觸發確認訂單
按鈕時,出現編號累加,後面緊接的是新的一筆訂單。
【成品】
【專案下載】