iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
Mobile Development

使用 SwiftUI 讓有趣的點子變成 Apps系列 第 20

D20 - 使用 SwiftUI 讓有趣的點子變成 Apps{無限猴子打字機: 專案}

  • 分享至 

  • xImage
  •  

和 D5 一樣手法,開一個無限猴子打字機的專案。

D5-葛麗絲逆走鐘: 開專案和畫上針

猴子打字機專案規格 (UI 部分)

  • 目標文字,讓使用者決定猴子的目標
  • 猴子的數量加減按扭,雖然原來的思想實驗是無限猴子,但程式沒有無限這個概念,仍然要有個數字。
  • 猴子開始打字的按鈕,按下去猴子會開始打字
  • 猴子停止打字的按鈕,按下去開始打字的猴子會停手
  • 打字紀錄區,雖然我們可以把結果噴到 console 上面,但使用者是看不到 console的。所以需要有個區域去紀錄猴子打出來的字。
  • 清掉打字的按鈕,讓下一個回合可以開始。這個按鈕就像 terminal 的 clear 指令

Demo UI

![https://ithelp.ithome.com.tw/upload/images/20220920/20140622EKdC56eJ9z.png]

這個 UI 用 SwiftUI 來做,是非常快的。下面這邊的程式碼,不含程式邏輯,單純 UI 排版。

struct InfiniteMonkeyTypingContentView: View {
    
    @State private var targetText = ""
    
    @State private var monkeyTyperCount = 1
    
    @State private var logText = ""
    
    @State private var textStyle = UIFont.TextStyle.body
    
    private var targetHint: String {
        if targetText.isEmpty {
            return "目前沒目標,請輸入目標文字在輸入框"
        }
        return "你的目標為: \(targetText)"
    }
    
    var body: some View {
        
        VStack {
            Text("無限猴子打字機")
                .font(.largeTitle)
                .padding(.top, 20)
            
            Text(targetHint)
                .lineLimit(1)
                .padding()
            
            TextField("請輸入目標", text: $targetText)
                .autocapitalization(.none)
                .padding()
                .textFieldStyle(.roundedBorder)
            
            monkeyTyperStepper
            
            monkeyActionButtons
            
            monkeyLogsAndClearLogs
            
            Rectangle()
                .foregroundColor(.white)
                .border(Color.blue)
                .padding()
            Spacer()
        }
    }
    
    private var monkeyTyperStepper: some View {
        HStack {
            Stepper("猴子數: \(monkeyTyperCount)") {
                stepperIncrease()
            } onDecrement: {
                stepperDecrease()
            }
        }
        .padding()
    }
    
    private var monkeyActionButtons: some View {
        HStack {
            Button("猴子停手") {
                // TODO: - 叫猴子停手
            }
            
            Button("叫猴子開始打字囉") {
                // TODO: - 叫猴子們開始打字
            }
        }
        .buttonStyle(.bordered)
        .padding()
    }
    
    private var monkeyLogsAndClearLogs: some View {
        HStack {
            Spacer()
            Text("猴子的打字紀錄")
            Button {
                // TODO: - 清掉打字
            } label: {
                Text("清除打字紀錄")
            }
            .padding(.leading, 20)
            .buttonStyle(.bordered)
            Spacer()
        }
    }
    
    private func stepperIncrease() {
        monkeyTyperCount += 1
    }
    
    private func stepperDecrease() {
        if monkeyTyperCount > 1 {
            monkeyTyperCount -= 1
        }
    }

}

上面的圖,是目標區沒有任何文字的 UI,如果我們打了一段字,UI 會提示我們目前的目標。就像下面這樣子。

https://ithelp.ithome.com.tw/upload/images/20220920/20140622FJHg2j3bUJ.png

打字紀錄區還未完成,下面這一段,事實上只是畫一個方形上去而已,這個 log 區有很多種做法。

          Rectangle()
                .foregroundColor(.white)
                .border(Color.blue)
                .padding()

用 UITextView 的做法

在以前 UIKit 的時代,我會讓 log 噴到 UITextView 上。UITextView 的元件可以裝載非….常多非常多的文字,而且已經自帶上下捲動功能,在設定上非常方便。

而這個做法,在 SwiftUI 時代,仍然可以使用,用 UIViewRepresentable 就能做到。

用 SwiftUI 元件 - List (當然可以用其他元件拼出來)

這是用 List 上下可滑動的特性,binding 一個 string array 後,SwiftUI 框架會自動更新 View。如果這個 list 長度不長的話,我個人覺得不會遇到效能的問題。但這個 log 功能,通常是把最新的紀錄,放在最上面 (當然,放在最下面也可以,Xcode console 就是放在最下面,但他有附加一直滾動的功能)。

如果設計成放講 list 最上方,就會需要一直把 log insert 到第 0 個位置。目前是沒有試到效能瓶頸,但沒有優化的狀況下,最後一定要遇到瓶頸。

我們可以等遇到了再說,或是,給予這個 log array 一個容量,只要超過這個容量,就把最舊的紀錄丟到。


上一篇
D19 - 無限猴子打字機 idea
下一篇
D21 - 使用 SwiftUI 讓有趣的點子變成 Apps{無限猴子打字機: 做出猴子}
系列文
使用 SwiftUI 讓有趣的點子變成 Apps30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言