Xcode 10.3
ios 12.4
swit5
ios 12.4
swit5
完成品
UI
今回はViewが多いですがなるべく標準に似せて設置しました。
コード
AppDelegate
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// 通知許可の取得
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .sound, .badge]){
(granted, _) in
if granted{
UNUserNotificationCenter.current().delegate = self
}
}
return true
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
let center = UNUserNotificationCenter.current()
center.getDeliveredNotifications { (notifications: [UNNotification]) in
for notification in notifications {
_ = AlarmVC.shared.getAlarm(from: notification.request.identifier)
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
}
}
}
}
extension AppDelegate: UNUserNotificationCenterDelegate{
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// アプリ起動中でもアラートと音で通知
completionHandler([.alert, .sound])
let uuid = notification.request.identifier
_ = AlarmVC.shared.getAlarm(from: uuid)
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let identifier = response.actionIdentifier
if identifier == "snooze"{
let snoozeAction = UNNotificationAction(
identifier: "snooze",
title: "Snooze 5 Minutes",
options: []
)
let noAction = UNNotificationAction(
identifier: "stop",
title: "stop",
options: []
)
let alarmCategory = UNNotificationCategory(
identifier: "alarmCategory",
actions: [snoozeAction, noAction],
intentIdentifiers: [],
options: [])
UNUserNotificationCenter.current().setNotificationCategories([alarmCategory])
let content = UNMutableNotificationContent()
content.title = "Snooze"
content.sound = UNNotificationSound.default
content.categoryIdentifier = "alarmCategory"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5 , repeats: false)
let request = UNNotificationRequest(identifier: "Snooze", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print(error.localizedDescription)
}
}
}
let uuid = response.notification.request.identifier
_ = AlarmVC.shared.getAlarm(from: uuid)
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
completionHandler()
}
}
AlarmVC
import UIKit
import UserNotifications
class AlarmVC: UIViewController,UITableViewDelegate,UITableViewDataSource {
static let shared = AlarmVC()
var appDelegate = UIApplication.shared
@IBOutlet weak var tableView: UITableView!
var userDefaults = UserDefaults.standard
var index:Int!
var timeArray:[AlarmTimeArray] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsSelectionDuringEditing = true
tableView.allowsSelection = false
tableView.register(UINib(nibName: "AlarmTimeCell", bundle: nil), forCellReuseIdentifier: "AlarmTimeCell")
self.navigationItem.setLeftBarButton(self.editButtonItem, animated: true)
timeLoad()
tableView.reloadData()
NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
}
@objc func methodOfReceivedNotification(notification: Notification) {
timeLoad()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func timeLoad(){
if let timeArrayData = UserDefaults.standard.object(forKey: "timeArray") as? Data {
if let getTimeArray = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(timeArrayData) as? [AlarmTimeArray] {
timeArray = getTimeArray
}
}
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: animated)
}
func setCellLabel(index:Int) -> String{
if timeArray[index].repeatLabel == "Never" {
return timeArray[index].label
}else{
return timeArray[index].label+","+timeArray[index].repeatLabel
}
}
func getAlarm(from uuid: String){
timeLoad()
guard let alarm = timeArray.first(where: { $0.uuidString == uuid }) else {return }
if alarm.week.isEmpty {
alarm.onOff = false
}
saveDate()
let center = UNUserNotificationCenter.current()
center.removeAllDeliveredNotifications()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return timeArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmTimeCell") as! AlarmTimeCell
cell.timeLabel.text = getTime(date: timeArray[indexPath.row].date)
cell.label.text = setCellLabel(index: indexPath.row)
cell.sw.isOn = timeArray[indexPath.row].onOff
cell.editingAccessoryType = .disclosureIndicator
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 画面遷移の準備
if tableView.isEditing {
index = indexPath.row
performSegue(withIdentifier: "showAlarmAdd", sender: nil)
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [timeArray[indexPath.row].uuidString])
timeArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
saveDate()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72
}
@IBAction func addButton(_ sender: Any) {
self.performSegue(withIdentifier: "showAlarmAdd", sender: nil)
}
func getTime(date:Date) -> String {
let f = DateFormatter()
f.timeStyle = .short
f.locale = Locale(identifier: "ja_JP")
return f.string(from: date)
}
func saveDate(){
let timeArrayData = try! NSKeyedArchiver.archivedData(withRootObject: timeArray, requiringSecureCoding: false)
userDefaults.set(timeArrayData, forKey: "timeArray")
userDefaults.synchronize()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showAlarmAdd"{
guard let nvc = segue.destination as? UINavigationController else {return}
guard let vc = nvc.topViewController as? AlarmAddVC else {return}
vc.delegate = self
vc.isEdit = tableView.isEditing
if tableView.isEditing {
vc.alarmTime = timeArray[index]
}
}
}
}
extension AlarmVC:AlarmAddDelegate{
func AlarmAddVC(alarmAdd: AlarmAddVC, alarmTime: AlarmTimeArray) {
if tableView.isEditing {
timeArray[index] = alarmTime
}else{
timeArray.append(alarmTime)
}
timeArray.sort(){$0.date < $1.date}
saveDate()
self.setEditing(false, animated: false)
tableView.reloadData()
}
func AlarmAddVC(alarmDelete: AlarmAddVC, alarmTime: AlarmTimeArray) {
self.setEditing(false, animated: false)
timeArray.remove(at: index)
saveDate()
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [timeArray[index].uuidString])
}
func AlarmAddVC(alarmCancel:AlarmAddVC){
self.setEditing(false, animated: false)
}
}
AlarmTimeCell
import UIKit
protocol AlarmTimeCellDelegate {
func alarmTimeCell(switchTappe:UITableViewCell,isOn:Bool)
}
class AlarmTimeCell: UITableViewCell {
@IBOutlet weak var timeLabel: UILabel!
@IBOutlet weak var label: UILabel!
@IBOutlet weak var sw: UISwitch!
override func awakeFromNib() {
super.awakeFromNib()
accessoryView = sw
}
}
AlarmAddVC
import UIKit
import UserNotifications
protocol AlarmAddDelegate {
func AlarmAddVC(alarmAdd:AlarmAddVC,alarmTime:AlarmTimeArray)
func AlarmAddVC(alarmDelete:AlarmAddVC,alarmTime:AlarmTimeArray)
func AlarmAddVC(alarmCancel:AlarmAddVC)
}
class AlarmAddVC: UIViewController ,UITableViewDelegate,UITableViewDataSource{
@IBOutlet weak var datePicker: UIDatePicker!
@IBOutlet weak var tableView: UITableView!
var delegate:AlarmAddDelegate!
var alarmTime:AlarmTimeArray = AlarmTimeArray()
var isEdit: Bool = false
var titleText = ["Repeat","Label","Sound"]
override func viewDidLoad() {
super.viewDidLoad()
datePicker.date = alarmTime.date
registerCell(cellName: "AlarmSnoozeCell")
registerCell(cellName: "AlarmAddCell")
registerCell(cellName: "AlarmDeleteCell")
tableView.tableFooterView = UIView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let indexPathForSelectedRow = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: indexPathForSelectedRow, animated: true)
}
}
//cell登録
func registerCell(cellName:String){
tableView.register(UINib(nibName: cellName, bundle: nil), forCellReuseIdentifier: cellName)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 4
case 1:
return 1
default:
return 0
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return isEdit ? 2:1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
switch indexPath.row{
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmAddCell") as! AlarmAddCell
cell.titleLabel.text = titleText[indexPath.row]
cell.subTitleLabel.text = alarmTime.repeatLabel
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmAddCell") as! AlarmAddCell
cell.titleLabel.text = titleText[indexPath.row]
cell.subTitleLabel.text = alarmTime.label
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmAddCell") as! AlarmAddCell
cell.titleLabel.text = titleText[indexPath.row]
cell.subTitleLabel.text = "Default"
cell.selectionStyle = .none
return cell
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmSnoozeCell") as! AlarmSnoozeCell
cell.delegate = self
cell.snoozeSwitch.isOn = alarmTime.snooze
return cell
default:
break
}
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmDeleteCell") as! AlarmDeleteCell
cell.delegate = self
return cell
default:
break
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.section {
case 0:
switch indexPath.row {
case 0:
self.performSegue(withIdentifier: "showRepeat", sender: nil)
case 1:
performSegue(withIdentifier: "showLabel",sender: nil)
break
case 2:break
default:break
}
default:
break
}
}
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 1 {
return 50
}else{
return 0
}
}
//アラーム設定時間を保存
@IBAction func saveButton(_ sender: Any) {
alarmSet()
delegate.AlarmAddVC(alarmAdd: self, alarmTime: alarmTime)
dismiss(animated: true, completion: nil)
}
//スヌーズ設定
func setCategories(){
let snoozeAction = UNNotificationAction(
identifier: "snooze",
title: "Snooze 5 Minutes",
options: []
)
let noAction = UNNotificationAction(
identifier: "stop",
title: "stop",
options: []
)
var alarmCategory:UNNotificationCategory!
if alarmTime.snooze {
alarmCategory = UNNotificationCategory(
identifier: "alarmCategory",
actions: [snoozeAction, noAction],
intentIdentifiers: [],
options: [])
}else{
alarmCategory = UNNotificationCategory(
identifier: "alarmCategory",
actions: [],
intentIdentifiers: [],
options: [])
}
UNUserNotificationCenter.current().setNotificationCategories([alarmCategory])
}
//通知設定
func setNotificationC(day:String, repeats:Bool){
let content = UNMutableNotificationContent()
content.title = alarmTime.label
content.sound = UNNotificationSound.default
content.categoryIdentifier = "alarmCategory"
var dateComponents = DateComponents()
if !day.isEmpty {
dateComponents.weekday = weekDay(day: day)
}
dateComponents.hour = Calendar.current.component(.hour, from: datePicker.date)
dateComponents.minute = Calendar.current.component(.minute, from: datePicker.date)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: repeats)
let request = UNNotificationRequest(identifier: alarmTime.uuidString+day, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print(error.localizedDescription)
}
}
alarmTime.date = datePicker.date
}
//アラート設定
func alarmSet(){
removeAlarm(identifiers: alarmTime.uuidString)
let shortWeekday = DateFormatter().shortWeekdaySymbols!
for i in shortWeekday {
removeAlarm(identifiers: alarmTime.uuidString+i)
}
if alarmTime.week.isEmpty {
setCategories()
setNotificationC(day:"", repeats: false)
}else{
for i in alarmTime.week {
setCategories()
setNotificationC(day: i, repeats: true)
}
}
}
//アラート設定削除
func removeAlarm(identifiers:String){
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifiers])
}
//曜日
func weekDay(day:String) -> Int{
var week = DateFormatter().weekdaySymbols!
switch day {
case week[0]:
return 1
case week[1]:
return 2
case week[2]:
return 3
case week[3]:
return 4
case week[4]:
return 5
case week[5]:
return 6
case week[6]:
return 7
default:
return Int()
}
}
//キャンセル
@IBAction func cancelButton(_ sender: Any) {
delegate.AlarmAddVC(alarmCancel: self)
dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier {
case "showRepeat":
guard let nextVC:AlarmRepeatVC = segue.destination as? AlarmRepeatVC else {return}
nextVC.delegate = self
nextVC.selectDay = alarmTime.week
case "showLabel":
guard let nextVC:AlarmAddLabelVC = segue.destination as? AlarmAddLabelVC else {return}
nextVC.delegate = self
nextVC.text = alarmTime.label
default:
return
}
}
}
extension AlarmAddVC:AlarmRepeatVCDelegate {
func AlarmRepeatVC(addRepeat: AlarmRepeatVC, week: [String]) {
alarmTime.week = []
alarmTime.repeatLabel = ""
alarmTime.week += week
if alarmTime.week.count == 1 {
alarmTime.repeatLabel = "Every"+alarmTime.week[0]
}else if alarmTime.week.isEmpty {
alarmTime.repeatLabel = "Never"
}else if alarmTime.week.count == 7{
alarmTime.repeatLabel = "Every day"
}else{
let shortWeekday = DateFormatter().shortWeekdaySymbols!
for i in alarmTime.week {
if alarmTime.repeatLabel != "" {
alarmTime.repeatLabel += ","
}
alarmTime.repeatLabel += shortWeekday[weekDay(day: i)]
}
}
tableView.reloadData()
}
}
extension AlarmAddVC:AlarmAddLabelDelegate {
func alarmAddLabel(labelText: AlarmAddLabelVC, text: String) {
alarmTime.label = text
tableView.reloadData()
}
}
extension AlarmAddVC:AlarmSnoozeCellDelegte{
func alarmSnoozeCell(swichOn: AlarmSnoozeCell, On: Bool) {
alarmTime.snooze = On
}
}
extension AlarmAddVC:AlarmDeleteCellDelegate{
func alarmDeleteCell(delete: UITableViewCell) {
delegate.AlarmAddVC(alarmDelete: self,alarmTime:alarmTime)
dismiss(animated: true, completion: nil)
}
}
AlarmAddCell
import UIKit
class AlarmAddCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subTitleLabel: UILabel!
}
AlarmSnoozeCell
import UIKit
protocol AlarmSnoozeCellDelegte {
func alarmSnoozeCell(swichOn:AlarmSnoozeCell,On:Bool)
}
class AlarmSnoozeCell: UITableViewCell {
@IBOutlet weak var snoozeSwitch: UISwitch!
var delegate:AlarmSnoozeCellDelegte!
@IBAction func switchChanged(_ sender: UISwitch) {
delegate.alarmSnoozeCell(swichOn: self, On: sender.isOn)
}
}
AlarmRepeatVC
import UIKit
protocol AlarmRepeatVCDelegate {
func AlarmRepeatVC(addRepeat:AlarmRepeatVC,week:[String])
}
class AlarmRepeatVC: UIViewController ,UITableViewDelegate,UITableViewDataSource{
@IBOutlet weak var tableView: UITableView!
var delegate:AlarmRepeatVCDelegate!
var week:[String] = []
var selectDay:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
// 複数選択可にする
tableView.allowsMultipleSelection = true
week = DateFormatter().weekdaySymbols!
}
override func viewWillDisappear(_ animated: Bool) {
delegate.AlarmRepeatVC(addRepeat: self, week:sortWeek(selectDays: selectDay))
}
func sortWeek(selectDays: [String]) -> [String]{
var week = DateFormatter().weekdaySymbols!
var dayDictionary: [String: Int] = [:]
for i in 0...6 {
dayDictionary[week[i]] = i
}
var daysOfWeek: [String] = selectDays
daysOfWeek.sort { (dayDictionary[$0] ?? 7) < (dayDictionary[$1] ?? 7)}
return daysOfWeek
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return week.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// セルを取得する
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "weekCell", for: indexPath)
cell.textLabel!.text = "Every"+week[indexPath.row]
cell.selectionStyle = .none
for i in selectDay {
if week[indexPath.row] == i {
cell.accessoryType = .checkmark
break
}else{
cell.accessoryType = .none
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at:indexPath)
// チェックマークを入れる
cell?.accessoryType = .checkmark
selectDay.append(week[indexPath.row])
}
// セルの選択が外れた時に呼び出される
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at:indexPath)
// チェックマークを外す
cell?.accessoryType = .none
selectDay = selectDay.filter { $0 != week[indexPath.row] }
}
}
AlarmAddLabelVC
import UIKit
protocol AlarmAddLabelDelegate {
func alarmAddLabel(labelText:AlarmAddLabelVC,text:String)
}
class AlarmAddLabelVC: UIViewController,UITextFieldDelegate {
var text:String!
@IBOutlet weak var textField: UITextField!
var delegate:AlarmAddLabelDelegate!
override func viewDidLoad() {
super.viewDidLoad()
// テキストを全消去するボタンを表示
textField.clearButtonMode = .always
// 改行ボタンの種類を設定
textField.returnKeyType = .done
// UITextFieldを追加
textField.delegate = self
//キーボードを表示する
textField.becomeFirstResponder()
textField.text = text
}
override func viewDidDisappear(_ animated: Bool) {
//textFieldの中身が空でない時
if textField.text != "", let text = textField.text{
delegate.alarmAddLabel(labelText: self, text:text)
}
}
// 完了ボタンを押した時の処理
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
//textFieldの中身が空でない時
if textField.text != "", let text = textField.text{
delegate.alarmAddLabel(labelText: self, text:text)
self.navigationController?.popViewController(animated: true)
}
return true
}
}
AlarmTimeArray
import UIKit
class AlarmTimeArray: NSObject,NSCoding {
var date:Date
var uuidString:String
var label:String
var sound:Bool
var snooze:Bool
var onOff:Bool
var repeatLabel:String
var week:[String]
override init() {
self.date = Date()
self.uuidString = UUID().uuidString
self.label = "Alarm"
self.sound = true
self.snooze = true
self.onOff = true
self.week = []
self.repeatLabel = "Never"
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.date, forKey: "date")
aCoder.encode(self.uuidString, forKey: "uuidString")
aCoder.encode(self.label, forKey: "label")
aCoder.encode(self.sound, forKey: "sound")
aCoder.encode(self.snooze, forKey: "snooze")
aCoder.encode(self.onOff, forKey: "onOff")
aCoder.encode(self.week, forKey: "week")
aCoder.encode(self.repeatLabel, forKey: "repeatLabel")
}
required init?(coder aDecoder: NSCoder) {
date = aDecoder.decodeObject(forKey: "date") as! Date
uuidString = aDecoder.decodeObject(forKey: "uuidString") as! String
label = aDecoder.decodeObject(forKey: "label") as! String
sound = aDecoder.decodeBool(forKey: "sound")
snooze = aDecoder.decodeBool(forKey: "snooze")
onOff = aDecoder.decodeBool(forKey: "onOff")
week = aDecoder.decodeObject(forKey: "week") as! [String]
repeatLabel = aDecoder.decodeObject(forKey: "repeatLabel") as! String
}
}
githubはこちら参考
UITableViewの編集モードを使ってCellの削除を実装するまでUITableViewのセルを選択不可にする方法
【Swift4】配列の中身(数値・文字・日付)を比較してソートする方法【Xcode9】
UITableViewでセルを複数選択する
【Swift】UserDefaultsに自作クラスのデータを保存する方法(iOS12対応)[Swift][Obj-C]UUIDStringの使い分け






0 件のコメント:
コメントを投稿