ساخت تایمر با Swift و SwiftUI — از صفر تا صد

در این مقاله قصد داریم اقدام به ساخت تایمر با Swift و SwiftUI بکنیم. بدین ترتیب در یک فرایند گام به گام از ابتدای طراحی یک اپلیکیشن تا اجرای نهایی تایمر کامل شده با روش برنامهنویسی سوئیفت و SwiftUI آشنا خواهید شد.
گام 1: آغاز پروژه جدید
یک پروژه جدید در Xcode باز کنید. قالب آن باید یک اپلیکیشن با «نمای منفرد» (Single View) باشد. زبان اپلیکیشن را روی سوئیفت تنظیم کنید و «رابط کاربری» (User Interface) را نیز روی SwiftUI قرار دهید. مقدار «نام محصول» (Product Name) را هر چه دوست دارید بگذارید. ما اپلیکیشن خود را Count Up Timer میگذاریم.
گام 2: افزودن متغیرها
در این بخش برخی متغیرها اضافه میکنیم تا ساعت، دقیقه و ثانیه را که باید روی صفحه نمایش یابند در خود ذخیره سازند. در فایل ContentView.swift خطوط 6 تا 8 قطعه کد زیر را اضافه کنید:
import SwiftUI struct ContentView: View { // Add lines 6 -> 8 @State var hours: Int = 0 @State var minutes: Int = 0 @State var seconds: Int = 0 var body: some View { Text("Hello, World!") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
این سه متغیر یعنی hours ،minutes و seconds با استفاده از پوشش مشخصه @State اعلان شدهاند تا در زمان تغییر یافتن مقدار، متن مربوطه بهروزرسانی شود.
گام 3: طراحی رابط کاربری
اکنون باید عملاً به طراحی UI بپردازیم. ما قصد داریم یک تایمر در میانه صفحه داشته باشیم و سپس دکمههای آغاز/مکث تایمر و ریست کردن تایمر روی صفر را قرار بدهیم. نخستین کاری که باید انجام دهیم افزودن یک VStack در body است. به این منظور روی Text(“Hello, World!”) راست-کلیک کرده و گزینه Embed in VStack را انتخاب کنید. اینک کد شما باید مانند زیر شده باشد:
var body: some View { VStack { Text("Hello, World!") } }
نمایش مقادیر تایمر
در ادامه باید متغیرها را مورد استفاده قرار دهیم. میخواهیم !Hello, World را به \(hours):\(minutes):\(seconds) تغییر دهیم. اگر بوم را باز کرده و آن را resume کنید، میبینید که مقدار 0:0:0 روی دستگاه نمایش مییابد.
شاید تعجب کنید که چرا از ساختار ()\ در پیرامون نام متغیر استفاده کردهایم. این ممیز و پرانتز به کامپایلر اعلام میکند که درون پرانتز، کدی قرار دارد. از این رو برنامه محتوای متغیر را به جای نام آن نمایش میدهد.
افزودن دکمه
اکنون زمان آن رسیده است که دکمهها را اضافه کرده و آنها را وادار به انجام دادن کاری بکنیم. ابتدا باید یک متغیر حالت جدید اضافه کنیم که مشخص سازد آیا تایمر آغاز شده یا مکث یافته است. درست پس از اعلان seconds مقدار زیر را اضافه میکنیم:
@State var timerIsPaused: Bool = true
سپس در ادامه ()Text باید یک گزاره if اضافه کنیم تا در زمان مکث یافتن تایمر یک نما دیده شود و در ادامه با راهاندازی مجدد پنهان شود. قطعه کد زیر این گزاره if را نمایش میدهد:
var body: some View { VStack { Text("\(hours):\(minutes):\(seconds)") if timerIsPaused { Text("PAUSED") } else { Text("NOT Paused") } } }
اینک باید Text را به Buttons عوض کنیم و از SF Symbol برای شروع، مکث و ریست کردن تایمر بهره بگیریم. اگر timerIsPaused مقدار true داشته باشد در این صورت باید یک آیکون play برای شروع تایمر نمایش دهیم و یک آیکون رو به عقب نیز برای ریست نمایش نمییابد. به این منظور باید از Image(systemName: String) به عنوان برچسبهای دکمه استفاده کنیم. این دو دکمه همچنین باید در یک HStack در کنار هم قرار بگیرند. اکنون اگر timerIsPaused مقدار false داشته باشد، باید یک آیکون مکث برای توقف تایمر نشان دهیم. قطعه کد زیر دکمهها را در یک گزاره if نمایش میدهد:
if timerIsPaused { HStack { Button(action:{ print("RESTART") }){ Image(systemName: "backward.end.alt") .padding(.all) } .padding(.all) Button(action:{ print("START") }){ Image(systemName: "play.fill") .padding(.all) } .padding(.all) } } else { Text("NOT Paused") }
گام 4: آغاز تایمر
اینک زمان آن رسیده است که تایمر آغاز شود. ما از Timer که یک کارکرد داخلی سوئیفت است، بهره میگیریم. باید یک تایمر تکراری بسازیم که در هر ثانیه یک ثانیه به مقدارش اضافه میشود. در ادامه یک متغیر برای حالت نخست اضافه میکنیم. بنابراین پس از timerIsPaused یک مقدار به صورت زیر اضافه میکنیم:
@State var timer: Timer? = nil
این دستور یک متغیر برای ذخیرهسازی تایمر در آن اعلان میکند، اما در عمل یک تایمر را هنوز در خود جای نداده است، چون در زمان آغاز به کار تایمر آن را اضافه خواهیم کرد.
سپس باید تابعی بنویسیم که تایمر را آغاز میکند و مقدار timerIsPaused را به false عوض میکند. نام این تابع را ()startTimer میگذاریم. در این تابع یک خط به صورت timerIsPaused = false اضافه میکنیم. سپس یک تایمر اضافه میشود. به قطعه کد زیر توجه کنید:
func startTimer(){ timerIsPaused = false // 1. Make a new timer timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true){ tempTimer in // 2. Check time to add to H:M:S if self.seconds == 59 { self.seconds = 0 if self.minutes == 59 { self.minutes = 0 self.hours = self.hours + 1 } else { self.minutes = self.minutes + 1 } } else { self.seconds = self.seconds + 1 } } }
در ادامه اتفاقاتی که در خطوط 3 تا 5 کد فوق میافتد را توضیح میدهیم.
ساخت یک تایمر جدید
این همان جایی است که تایمر عملاً ساخته میشود. ما از یک تایمر زمانبندی استفاده میکنیم که هر ثانیه یک بار چیزی را تحریک میکند.
- withTimeInterval – برای تعیین فراوانی هر عمل که درون کلوژر اجرا میشود بر حسب ثانیه مورد استفاده قرار میگیرد. مقدار آن را روی یک تعیین کردهایم تا seconds هر ثانیه یک واحد افزایش یابد.
- Repeats – این مقدار باید روی true تنظیم شود تا کد درون کلوژر هر ثانیه یک بار اجرا شود. اگر مقدار آن false باشد، عملیات درون کلوژر تنها یک بار اجرا خواهد شد.
بررسی زمان برای افزودن
در کد زیر بررسی میکنیم چه زمانی باید مقادیر متغیرهای seconds ،minutes و hours افزایش یابند. ما از متد کلوژر برای آغاز یک تایمر جدید استفاده کردهایم تا تابع را در یک فراخواننده Objective-C قرار ندهیم. زمانی که تابع نوشته شد، باید مطمئن شویم که آن را در یک دکمه فراخوانی میکنیم. کد دکمه شروع به صورت زیر است:
Button(action:{ self.startTimer() }){ Image(systemName: "play.fill") .padding(.all) } .padding(.all)
گام 5: توقف تایمر
اینک زمان کدنویسی یک کارکرد دیگر تایمر یعنی متوقف ساختن آن رسیده است. این تابع را ()stopTimer مینامیم. در این تایمر باید مقدار timerIsPaused را به صورت false تعیین کنیم و تایمری که هم اینک کار میکند را از بین ببریم. برای از بین بردن تایمر باید تابع ()invalidate را روی تایمر فراخوانی کنیم که امکان آغاز مجدد تایمر را نمیدهد. کد تابع به صورت زیر است:
func stopTimer(){ timerIsPaused = true timer?.invalidate() timer = nil }
اینک باید مطمئن شویم که وقتی دکمه Stop زده میشود، تابع فراخوانی خواهد شد. بدین ترتیب فایل ContentView.swift تا اینجا به صورت زیر درآمده است:
// // ContentView.swift // count-up-timer // // Created by Maegan Wilson on 4/28/20. // Copyright © 2020 Maegan Wilson. All rights reserved. // import SwiftUI struct ContentView: View { @State var hours: Int = 0 @State var minutes: Int = 0 @State var seconds: Int = 0 @State var timerIsPaused: Bool = true @State var timer: Timer? = nil var body: some View { VStack { Text("\(hours):\(minutes):\(seconds)") if timerIsPaused { HStack { Button(action:{ print("RESTART") }){ Image(systemName: "backward.end.alt") .padding(.all) } .padding(.all) Button(action:{ self.startTimer() print("START") }){ Image(systemName: "play.fill") .padding(.all) } .padding(.all) } } else { Button(action:{ print("STOP") self.stopTimer() }){ Image(systemName: "stop.fill") .padding(.all) } .padding(.all) } } } func startTimer(){ timerIsPaused = false timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true){ tempTimer in if self.seconds == 59 { self.seconds = 0 if self.minutes == 59 { self.minutes = 0 self.hours = self.hours + 1 } else { self.minutes = self.minutes + 1 } } else { self.seconds = self.seconds + 1 } } } func stopTimer(){ timerIsPaused = true timer?.invalidate() timer = nil } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
گام 6: ریست کردن ساعت
این سادهترین تابع پروژه ما است. کافی است مقادیر متغیرهای hour ،minutes و seconds را روی صفر تنظیم کنیم.
func restartTimer(){ hours = 0 minutes = 0 seconds = 0 }
اکنون زمانی که دکمه reset زده شود، با استفاده از ()self.restartTimer آن را فراخوانی میکنیم. بدین ترتیب کار طراحی تایمر ما به پایان میرسد.
کد کامل این پروژه را میتوانید در این ریپوی گیتلب (+) مشاهده کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- آموزش برنامه نویسی Swift (سوئیفت) برای برنامه نویسی iOS
- مجموعه آموزشهای دروس علوم و مهندسی کامپیوتر
- آموزش سوئیفت (Swift) — مجموعه مقالات مجله فرادرس
- ساخت اپلیکیشن چت برای iOS با SwiftUI — از صفر تا صد
==