技術筆記-iOS實戰003-取用SwiftUI之必要元件,搭配資料處理技術,組成一個有意義的應用

更新 發佈閱讀 13 分鐘

需求情境:

一般的看盤軟體,雖然都能針對一籃子自選股票,列出其即時行情和當天漲幅,但若要看「五日漲幅」呢?那就少見了,但這對我很重要。因為小部位的波段性價差交易是個好策略,這時候若能排序好一整排看下來,可以節省大量點來點去的成本,很有價值,所以就來自己刻。

解決方案:

從大處著眼,UI 最外層需要一個可上下捲動的容器,就是 ScrollView;容器裡面放一個類似表格的結構。雖然 SwiftUI 有一個 Table 元件,但它預設是給 iPad 使用的,在iPhone 上顯示會很奇怪,只會顯示一行,也不會有標題,然後沒有任何提示說資料顯示不完全,簡直是莊孝維,完全不可用,故放棄之,改用 Grid 取代之。資料排列整齊之後,希望能夠按標題排序,切換正序或倒序。另外也須希望能夠切換觀察漲幅的基準是一日或五日,所以又會用到 Picker 這種元件,然後取用上一篇 iOS實戰002 裡面資料處裡的技術成果,搭配起來,讓功能水準得到一次顯著提升。

實作步驟:

最完整的文件就在原始碼裡面。以下程式重點為,以 ScrollView and Grid 為最外層容器,裡面一行一行以 GridRow 依序展開。第一行為標題,三個欄位固定只有文字,第四個欄位就比較特別了,是由一個 Button 組成,點下去會排序,排序完後順便把控制排序順序的變數 sortDirection 變號,使下一次再按時變成順序顛倒。

接下來跑一個迴圈,每一筆資料產生一個 GridRow,裡面包含四個欄位的資料格內容,為了讓每一格顯示上下兩項資料,所以又用 VStack 包起來。第一格的 Symbol 部分,用之前系統設計既有風格的自訂顏色,最後一個則動態指定顏色,漲時紅色,跌時綠色,事就這樣成了。

ScrollView {
Grid {
GridRow() {
Text("Symbol")
Text("Base Day")
Text("Price")
HStack {
Button(action: {
self.newDashItems.sort(by: {
a, b in
a.chgRate*sortDirection < b.chgRate*sortDirection
})
sortDirection *= (-1.0)
},
label: {
Text("Change")
Image(systemName: "chevron.up.chevron.down")
})
}
}
.font(.headline)
.fontWeight(.bold)
.background()

Divider()

ForEach(newDashItems) { item in
GridRow {
//DashItemView(item: item)
VStack {
let symbolStr = item.symbol.replacingOccurrences(of: ".TWO", with: "").replacingOccurrences(of: ".TW", with: "")
Text(symbolStr)
.padding(3)
.foregroundColor(Color(red: 181/255.0, green: 81/255.0, blue: 81/255.0))
.background(Color(red: 242/255.0, green: 244/255.0, blue: 244/255.0), in: RoundedRectangle(cornerRadius: 8))
.fontWeight(Font.Weight.bold)
.padding(3)
Text("\(item.name)")
.fontWeight(.bold)
}
VStack {
Text(item.baseDay.suffix(4))
let baseCloseString = String(format: "%.2f", item.baseClose)
Text(baseCloseString)
}
VStack {
let lastTimeValue = item.dataList[item.dataList.count-1]
Text(lastTimeValue.time.suffix(9))
let newValueString = String(format: "%.2f", item.dataList[item.dataList.count-1].value)
HStack {
Text("\(newValueString)")
}
}
VStack {
let iconColor = item.chgRate > 0 ? Color.red : Color.green
let chgRateStr = String(format: "%.1f", item.chgRate*100)
Text("\(chgRateStr) %")
.foregroundColor(iconColor)
}
}
Divider()
}
}
}
.onAppear {
getDashItemsFromFile()
}

以下兩畫面分別顯示一日漲幅與五日漲幅,格式均相同,只是 Base Day 的內容被抽換了,後面繼續說明資料處理部分的程式。

vocus|新世代的創作平台

按下 Picker day1 or day5 的動作如下:

先宣告狀態變數 baseDayOption,屬於自訂列舉型別 BaseDayOption,具有預設值 day1,按下按鈕時,將原始從後台接收的 dashItems 用 map 函數映射成另一個陣列 newDashItems,根據選項重先設定 baseDay, baseClose, chgRate,UI 元件則設定好會顯示新的陣列。

@State private var baseDayOption: BaseDayOption = .day1
enum BaseDayOption {
case day1
case day5
}

func computeNewItems() {
switch baseDayOption {
case .day1:
newDashItems = dashItems.map { item in
var newItem = item
newItem.baseDay = item.lastCloseDay
newItem.baseClose = item.lastClose
newItem.chgRate = (item.dataList[item.dataList.count-1].value - item.lastClose) / item.lastClose
return newItem
}
case .day5:
newDashItems = dashItems.map { item in
var newItem = item
newItem.baseDay = item.last5Day
newItem.baseClose = item.last5Close
newItem.chgRate = (item.dataList[item.dataList.count-1].value - item.last5Close) / item.last5Close
return newItem
}
}
}

因為 baseDay,baseClose,chgRate 三個欄位是計算欄位,後台傳回時並沒有,因此在 decode 時會出錯,因此必須重新定義初始化函示 init(),在其中指定預設值,讓 decoder 可順利運作:

struct DashItem: Codable, Identifiable {
    let alertId: Int
    let symbol: String 
    let name: String
    let lastCloseDay: String
    let last5Day: String
    let lastClose: Double
    let last5Close: Double
    let dataList: [TimeValue]
    var id: Int {
        alertId
    }
    
    var baseDay: String
    var baseClose: Double
    var chgRate: Double
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        alertId = try container.decode(Int.self, forKey: .alertId)
        symbol = try container.decode(String.self, forKey: .symbol)
        name = try container.decode(String.self, forKey: .name)
        lastCloseDay = try container.decode(String.self, forKey: .lastCloseDay)
        last5Day = try container.decode(String.self, forKey: .last5Day)
        lastClose = try container.decode(Double.self, forKey: .lastClose)
        last5Close = try container.decode(Double.self, forKey: .last5Close)
        dataList = try container.decode([TimeValue].self, forKey: .dataList)
        baseDay = ""
        baseClose = 0
        chgRate = 0
    }
}

struct TimeValue: Codable {
    let time: String
    let value: Double
}

至於系統增加顯示檔案更新的時間,使用以下程式:

func getFileDatetime(fileName: String) -> Date? {
let filePath = getDocumentDirectory().appendingPathComponent(fileName)
do {
let attributes = try FileManager.default.attributesOfItem(atPath: filePath.path)
if let modificationDate = attributes[FileAttributeKey.modificationDate] as? Date {
return modificationDate
} else {
return nil
}
} catch {
return nil
}
}

技術掌握狀況盤點:

資料部分:

  1. 呼叫 REST api,接收 json 資料並解碼,特定欄位不解碼,塞預設值。
  2. 非同步呼叫,程序獨立成 service 模組,並非同步接收回傳值與 UI 渲染。
  3. 陣列的 map 操作,sort 操作。
  4. 本地端 DocumentDirectory 裡的檔案儲存,讀取。

UI 部分:

  1. Layout:ScrollView,GridView,VStack,HStack
  2. 元件:Text,Image,Button,Picker


Newman 2024/6/20

導覽頁:紐曼的技術筆記-索引









留言
avatar-img
newman的沙龍
32會員
151內容數
漫步是一種境界。
newman的沙龍的其他內容
2025/04/01
Reinforcement Learning (強化學習) 的理論非常有趣,可能是因為其中許多方法,與人類的學習歷程極為相似,如試錯,獎懲,改進策略,持續優化等等。現在準備來爬這座山了,我把學習階段大致分成三個小山峰,依序為 Q-Learning --> DQN --> Actor-Critic,
Thumbnail
2025/04/01
Reinforcement Learning (強化學習) 的理論非常有趣,可能是因為其中許多方法,與人類的學習歷程極為相似,如試錯,獎懲,改進策略,持續優化等等。現在準備來爬這座山了,我把學習階段大致分成三個小山峰,依序為 Q-Learning --> DQN --> Actor-Critic,
Thumbnail
2025/03/08
稍微看一下 Telegram 官方文件,哇!好強喔,功能說明的第一項赫然出現「可以取代整個網站」!口氣真的很大。雖然我的需求應該很低,但能夠確認前面是一座豐富的寶藏,還是很令人興奮的,待基本功能掌握之後,可以再評估和決定要不要往下挖。 發送訊息 要達成這第一個目標,首先必須建立一個 bot。
Thumbnail
2025/03/08
稍微看一下 Telegram 官方文件,哇!好強喔,功能說明的第一項赫然出現「可以取代整個網站」!口氣真的很大。雖然我的需求應該很低,但能夠確認前面是一座豐富的寶藏,還是很令人興奮的,待基本功能掌握之後,可以再評估和決定要不要往下挖。 發送訊息 要達成這第一個目標,首先必須建立一個 bot。
Thumbnail
2025/03/01
Line Notify 即將停止服務,隨著時間越來越緊迫,隱約聽到許多人在哀嚎。印象中有許多廠商,把 Line Notify 用得淋漓盡致,甚至可以一個客戶建一個群組,把許多客製化服務都用程式管理的井井有條,得到很好的滿意度。但這種好康,無限免費的即時訊息,沒有了,時間就在 2025/3/31!公告
Thumbnail
2025/03/01
Line Notify 即將停止服務,隨著時間越來越緊迫,隱約聽到許多人在哀嚎。印象中有許多廠商,把 Line Notify 用得淋漓盡致,甚至可以一個客戶建一個群組,把許多客製化服務都用程式管理的井井有條,得到很好的滿意度。但這種好康,無限免費的即時訊息,沒有了,時間就在 2025/3/31!公告
Thumbnail
看更多
你可能也想看
Thumbnail
需求情境: 一般的看盤軟體,雖然都能針對一籃子自選股票,列出其即時行情和當天漲幅,但若要看「五日漲幅」呢?那就少見了,但這對我很重要。因為小部位的波段性價差交易是個好策略,這時候若能排序好一整排看下來,可以節省大量點來點去的成本,很有價值,所以就來自己刻。 解決方案: 從大處著眼,UI 最外層
Thumbnail
需求情境: 一般的看盤軟體,雖然都能針對一籃子自選股票,列出其即時行情和當天漲幅,但若要看「五日漲幅」呢?那就少見了,但這對我很重要。因為小部位的波段性價差交易是個好策略,這時候若能排序好一整排看下來,可以節省大量點來點去的成本,很有價值,所以就來自己刻。 解決方案: 從大處著眼,UI 最外層
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
重視籌碼分析 基本面跟技術面需要去研究線圖指標或財報等財務資訊 但籌碼只要花點時間研究或許就能看出端倪 過往刻意選了本身股性比較活潑的個股股票 經過思考之後 從今開始會改變一下分享的個股 會開始帶一些用分點進出判斷多空 即便如此 停損停利的重要性還是要有 不如預期 一定要
Thumbnail
重視籌碼分析 基本面跟技術面需要去研究線圖指標或財報等財務資訊 但籌碼只要花點時間研究或許就能看出端倪 過往刻意選了本身股性比較活潑的個股股票 經過思考之後 從今開始會改變一下分享的個股 會開始帶一些用分點進出判斷多空 即便如此 停損停利的重要性還是要有 不如預期 一定要
Thumbnail
保持理性面對市場波動,避免過度對沖和降低槓桿,監控日元匯率,並保持長期投資視角。了解市場調整期的應對策略、事件型交易的操作技巧,以及行業領頭羊的動向。關注經濟數據和市場傳聞,靈活調整投資策略,確保投資決策基於充分的信息和合理的分析。
Thumbnail
保持理性面對市場波動,避免過度對沖和降低槓桿,監控日元匯率,並保持長期投資視角。了解市場調整期的應對策略、事件型交易的操作技巧,以及行業領頭羊的動向。關注經濟數據和市場傳聞,靈活調整投資策略,確保投資決策基於充分的信息和合理的分析。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
介紹了股票投資時常用的市場面指標、基本面指標、技術面指標、籌碼面指標、財務面指標等。並聚焦於淨值、總市值和股本的相關補充內容。
Thumbnail
介紹了股票投資時常用的市場面指標、基本面指標、技術面指標、籌碼面指標、財務面指標等。並聚焦於淨值、總市值和股本的相關補充內容。
Thumbnail
本文介紹了作者對股債配置的看法,以及使用EXCEL統整的效率方法。並提及近期債市崩跌、高息型商品不再增加等策略。期望讀者能從中獲得市場贏家的啟示。
Thumbnail
本文介紹了作者對股債配置的看法,以及使用EXCEL統整的效率方法。並提及近期債市崩跌、高息型商品不再增加等策略。期望讀者能從中獲得市場贏家的啟示。
Thumbnail
重視籌碼分析 基本面跟技術面需要去研究線圖指標或財報等財務資訊 但籌碼只要花點時間研究或許就能看出端倪 改變一下分享的個股 即便如此 停損停利的重要性還是要有 萬一不如預期 一定要果斷停損 避免讓傷害擴大
Thumbnail
重視籌碼分析 基本面跟技術面需要去研究線圖指標或財報等財務資訊 但籌碼只要花點時間研究或許就能看出端倪 改變一下分享的個股 即便如此 停損停利的重要性還是要有 萬一不如預期 一定要果斷停損 避免讓傷害擴大
Thumbnail
重視籌碼分析 基本面跟技術面需要去研究線圖指標或財報等財務資訊 但籌碼只要花點時間研究或許就能看出端倪 分點解析搭配技術型態也常能搭上主力的順風車 跟著勝利券商操作 勝率也能大大提升! 改變一下分享的個股 即便如此 停損停利的重要性還是要有 萬一不如預期 一定要果斷停損 避
Thumbnail
重視籌碼分析 基本面跟技術面需要去研究線圖指標或財報等財務資訊 但籌碼只要花點時間研究或許就能看出端倪 分點解析搭配技術型態也常能搭上主力的順風車 跟著勝利券商操作 勝率也能大大提升! 改變一下分享的個股 即便如此 停損停利的重要性還是要有 萬一不如預期 一定要果斷停損 避
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
本文章內容涉及股市指標包括市場面、基本面、技術面、籌碼面和財務面指標,以及股價、漲跌幅度、成交量、主力買賣超、貝塔值等相關內容。這些指標對於選股時常用的多個維度提供了綜合評價,投資者可根據自己的策略採用不同組合的指標進行分析。
Thumbnail
本文章內容涉及股市指標包括市場面、基本面、技術面、籌碼面和財務面指標,以及股價、漲跌幅度、成交量、主力買賣超、貝塔值等相關內容。這些指標對於選股時常用的多個維度提供了綜合評價,投資者可根據自己的策略採用不同組合的指標進行分析。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News