公開中のアプリ

[Swift/Xcode]初心者必見!iOSアプリ作成から公開まで徹底解説!#23「データリセット機能実装編」

今回はメニュー画面のデータリセット機能を実装したいと思います!

簡単に実装できると思ってたんですけどちょっとハマりました(^^;

動作環境は下記の通りです!
Xcode Version 12.5 Swift version 5.4

実装の流れ

まずは実装の流れから簡単に説明します!
データリセットのセルを押したら、まずアラートを出して本当に削除するか確認してあげたいと思います。
そのアラートでOKを押したらデータを削除します。

こんな感じです!

削除確認のアラートの実装

とりあえず「データリセット」を押した時にアラートを出してあげます!
OKボタンとキャンセルボタンのあるアラートは以前やりましたね!

ちょっとコードが長くなりますのでメソッドを作ってまとめちゃいましょう!

func deleteAlert() {
    //タイトルとメッセージの設定
    let alertController = DOAlertController(title: "本当に削除しますか?", message: "削除すると元には戻せません!", preferredStyle: .alert)
    //キャンセルボタンの設定
    let cancelAction = DOAlertAction(title: "Cancel", style: .cancel, handler: nil)
    //OKボタンの設定
    let okAction = DOAlertAction(title: "OK", style: .default) { action in
        //メインビューコントローラー取得
        let nc = self.presentingViewController as! UINavigationController
        let vcNum = nc.viewControllers.count
        let firstVC = nc.viewControllers[vcNum - 1] as! MainViewController
        //先に色とか変更しちゃう
        firstVC.deleteAlertBack()
        //realmDBを全て削除
        let realm = try! Realm()
        try! realm.write {
          realm.deleteAll()
        }
    }

    // アラートビューの背景色
    alertController.alertViewBgColor = UIColor.white
    alertController.alertView.layer.cornerRadius = 15
    // タイトルのフォント、文字色
    alertController.titleFont = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.titleTextColor = UIColor(hex: "8a6b52", alpha: 1)
    alertController.messageFont = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.messageTextColor = UIColor.red
    //キャンセルボタンの設定
    alertController.buttonFont[.cancel] = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.buttonBgColor[.cancel] = UIColor(hex: common.main, alpha: 1)
    alertController.buttonBgColorHighlighted[.cancel] = UIColor(hex: common.main, alpha: 1)
    //OKボタンの設定
    alertController.buttonFont[.default] = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.buttonBgColor[.default] = UIColor.red
    alertController.buttonBgColorHighlighted[.default] = UIColor.red

    // アラートコントローラにアクションを追加
    alertController.addAction(cancelAction)
    alertController.addAction(okAction)

    // 表示
    present(alertController, animated: true, completion: nil)
}

色などの設定はコメントを見ればわかると思います!

ちょっと説明したいのが、OKボタンを押した時の処理です。

OKボタンを押したらRealmのデータを全部削除するんですけど、その前にやらないといけない事があります!

メイン画面のボタンの色や貯金額を元に戻さないといけないんです!

ちょっとややこしいんですけど、まずOKを押した時に処理されるメソッドの中でMainViewControllerを取得して、MainViewController.swiftに書いてるメソッドをMenuViewController.swiftでも使えるようにしています!

それが9行目〜11行目のコードになります。

そして、13行目のdeleteAlertBack()がMainViewControllerのメソッドです!

まだdeleteAlertBack()を書いていないので、MainViewController.swiftに追加します!

func deleteAlertBack() {
    //realmの呼び出し
    let realm = try! Realm()
    //保存されたデータが定数Btn365に入る
    let Btn365 = realm.objects(Btn365.self)
    //定数Btn365をfor文で回し、ボタンの色を変更しつつ、貯金額を足しつつ、日数も足してる。
    for i in 0..<Btn365.count {
        //アクティブなボタンの色を緑に設定
        buttonArray[Btn365[i].tagNum - 1].backgroundColor = UIColor(hex: self.common.white , alpha: 1)
        //ボタンの色が緑の場合、テキストの色は白にしたいので白に設定
        self.buttonArray[Btn365[i].tagNum - 1].setTitleColor(UIColor(hex: self.common.text , alpha: 1), for: UIControl.State())
    }
    //貯金額ラベルを更新
    moneyLabel.text = "貯金額 \(0)円"
    //合計日数ラベルを更新
    dayLabel.text = "\(0)日目"
}

あとは、switch文のcase4でdeleteAlert()を実行すればOKです!

//セルを選択した時の設定
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  print("Selected! \(self.items[indexPath.row])")
    switch indexPath.row {
    case 0:
        print("アラーム設定画面へ")
    case 1:
        print("ウォークスルー画面へ")
    case 2:
        print("シェア")
        share()
    case 3:
        print("評価")
        //レビューダイアログを表示
        if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
            SKStoreReviewController.requestReview(in: scene)
        }
    case 4:
        print("データリセット")
        deleteAlert()

    default:
        break
        }
    }

これで一度ビルドして確認してみましょう!

アラートのOKボタンを押してから戻るとちゃんとデータが消えてると思います!

これで完了でもいいんですけど、データが消えたら「データを削除しました」的なアラートを出してあげたいと思います!

Realmのデータ変更を検知する

データが削除されたかどうか検知してあげて、検知できたらアラートを出してあげれば良さそうですね!

まずはMenuViewController.swiftに下記コードを追加しましょう!

//Realm通知
var token : NotificationToken?

次にviewDidLoad()内に下記コードを追加すればOKです!

//Realmのデータが更新されたら検知する
let realm = try! Realm()
token = realm.observe({ (notification:Realm.Notification, realm) in
  print("realm is updated")
    //アラートの表示
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        let alertController = self.common.originalAlert(title: "削除しました", message: "")
        self.present(alertController, animated: true, completion: nil)
    }
})

アラートのコードは7行目と8行目だけですけど、そのままだとアラートが表示されなかったので、0.5秒遅らせてアラートを出すようにしました!

Realmのデータ変更の検知ですが、もっと詳細に検知する事も可能なようなので興味ある方はググってみて下さい〜!

忘れてました!
アラートを簡単に使えるようにCommon.swiftに下記コードを追加しました!

func originalAlert(title: String, message: String) -> DOAlertController {
    // アラートコントローラ: タイトル、メッセージ、アラートスタイル(Alert/ActionSheet)を設定
    let alertController = DOAlertController(title: title, message: message, preferredStyle: .alert)
    
    // アクション: ボタンの文字、ボタンスタイル(Default/Cancel/Destructive)、ボタンを押した時の処理を設定
    let cancelAction = DOAlertAction(title: "OK", style: .cancel, handler: nil)
    
    // アラートビューの背景色
    alertController.alertViewBgColor = UIColor.white
    alertController.alertView.layer.cornerRadius = 15
    // タイトルのフォント、文字色
    alertController.titleFont = UIFont(name: "HiraMaruProN-W4", size: 14)
    alertController.titleTextColor = UIColor(hex: text, alpha: 1)
    
    alertController.messageTextColor = UIColor(hex: text, alpha: 1)
    alertController.messageFont = UIFont(name: "HiraMaruProN-W4", size: 14)
    // ボタンのフォント、文字色、背景色(通常時/ハイライト時)
    // [.Default]を[.Cancel][.Destructive]に変更すればそれぞれのアクションごとにボタンのカスタマイズが可能
    alertController.buttonFont[.cancel] = UIFont(name: "HiraMaruProN-W4", size: 17)
    //            alertController.buttonTextColor[.cancel] = UIColor(hex: "66b9bf", alpha: 1)
    alertController.buttonBgColor[.cancel] = UIColor(hex: main, alpha: 1)
    alertController.buttonBgColorHighlighted[.cancel] = UIColor(hex: main, alpha: 1)
    
    // アラートコントローラにアクションを追加
    alertController.addAction(cancelAction)

    return alertController
}

まとめ

メニュー画面の実装も残り二つですね!

使い方に関してはウォークスルーで良いと思うので最後の方に実装します!

なので次はアラームの実装をやります!

ちょっと自信ないので心配ですが近々更新したいと思います!

ここまで読んでくれた方、本当にありがとうございます。

修正したコード全部

MainViewController.swift

import UIKit
import AudioToolbox
import RealmSwift

class MainViewController: UIViewController {

//スクロールビュー
let scrollView = UIScrollView()
//ボタンを表示用のビュー
let inView: UIView = UIView()
//スタックビュー縦用
var stackV: UIStackView = UIStackView()
//ボタンの配列
var buttonArray: [UIButton] = []
//スタックビュー横を格納する為の配列
var stkArray: [UIStackView] = []
//貯金額合計
var totalSavings = 0
//貯金開始?日目
var whatDay = 0
// DB参照ボタン
var menuBtn: UIBarButtonItem!
//DBリセットボタン
var resetBtn: UIBarButtonItem!

//オレンジ色のビュー
let topView: UIView = UIView()
//白色のビュー
let topViewInner: UIView = UIView()
//合計日数のラベル
let dayLabel: UILabel = UILabel()
//貯金額のラベル
let moneyLabel: UILabel = UILabel()
//Commonクラスのインスタンス生成
let common = Common()

override func viewDidLoad() {
super.viewDidLoad()
    
//ビューの生成
viewCreate()
//ラベルの生成
labelCreate()
//ボタンの生成
btnCreate()
//スタックビューの生成
stackViewCreate()

//ナビゲーションコントローラーまわり
//タイトル
self.title = "Bank365"
//背景色
self.navigationController?.navigationBar.barTintColor = UIColor(hex: self.common.main , alpha: 1)
//セーフエリアとの境目の線を消す
self.navigationController?.navigationBar.shadowImage = UIImage()
//フォントの設定
self.navigationController?.navigationBar.titleTextAttributes
    = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "HiraMaruProN-W4", size: 20)!]
    
//背景色の設定
self.view.backgroundColor = UIColor(hex: common.background , alpha: 1)
    
//メニューボタン
menuBtn = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), style: .done, target: self, action: #selector(self.menuBtnTapped))
menuBtn.tintColor = UIColor(hex: self.common.white , alpha: 1)
self.navigationItem.rightBarButtonItem = menuBtn
    
//Realmテスト用ボタン左
resetBtn = UIBarButtonItem(title: "リセット", style: .done, target: self, action: #selector(self.resetBtnTapped))
self.navigationItem.leftBarButtonItem = resetBtn

//realmの呼び出し
let realm = try! Realm()
//保存されたデータが定数Btn365に入る
let Btn365 = realm.objects(Btn365.self)
//定数Btn365をfor文で回し、ボタンの色を変更しつつ、貯金額を足しつつ、日数も足してる。
for i in 0..<Btn365.count {
    //アクティブなボタンの色を緑に設定
    buttonArray[Btn365[i].tagNum - 1].backgroundColor = UIColor(hex: self.common.sub , alpha: 1)
    //ボタンの色が緑の場合、テキストの色は白にしたいので白に設定
    self.buttonArray[Btn365[i].tagNum - 1].setTitleColor(UIColor(hex: self.common.white , alpha: 1), for: UIControl.State())
    //貯金額を足してる
    totalSavings += Btn365[i].tagNum
    //日数はアクティブなボタンの数と同じ
    whatDay += 1
}
//貯金額ラベルを更新
moneyLabel.text = "貯金額 \(totalSavings)円"
//合計日数ラベルを更新
dayLabel.text = "\(whatDay)日目"
}

//メニュー画面へ遷移させるメソッド+DB参照
@objc func menuBtnTapped() {
    let realm = try! Realm()
    let Btn365 = realm.objects(Btn365.self)
    print(Btn365)
    
    let MenuViewController = MenuViewController.init()
    let NV = UINavigationController.init(rootViewController: MenuViewController)
    present(NV, animated: true, completion: nil)
}
    
func deleteAlertBack() {
    //realmの呼び出し
    let realm = try! Realm()
    //保存されたデータが定数Btn365に入る
    let Btn365 = realm.objects(Btn365.self)
    //定数Btn365をfor文で回し、ボタンの色を変更しつつ、貯金額を足しつつ、日数も足してる。
    for i in 0..<Btn365.count {
        //アクティブなボタンの色を緑に設定
        buttonArray[Btn365[i].tagNum - 1].backgroundColor = UIColor(hex: self.common.white , alpha: 1)
        //ボタンの色が緑の場合、テキストの色は白にしたいので白に設定
        self.buttonArray[Btn365[i].tagNum - 1].setTitleColor(UIColor(hex: self.common.text , alpha: 1), for: UIControl.State())
    }
    //貯金額ラベルを更新
    moneyLabel.text = "貯金額 \(0)円"
    //合計日数ラベルを更新
    dayLabel.text = "\(0)日目"
}
//DBリセット
@objc func resetBtnTapped() {
    let realm = try! Realm()
    try! realm.write {
      realm.deleteAll()
    }
}
    
//ビュー生成
func viewCreate() {
    //オレンジ色のビューの表示
    view.addSubview(topView)
    //白色のビューの表示
    topView.addSubview(topViewInner)
    //スクロールビューの表示
    view.addSubview(scrollView)
    //ボタン表示用ビューの表示
    scrollView.addSubview(inView)

    //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    //スクロールビューの上側の位置を設定
    scrollView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: 20.0).isActive = true
    //スクロールビューの下側の位置を設定
    scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20.0).isActive = true
    //Y軸
    scrollView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
    //横幅
    scrollView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 0.95).isActive = true


    //ボタン表示用ビューの設定
    //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
    inView.translatesAutoresizingMaskIntoConstraints = false
    //横幅
    inView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0).isActive = true
    //この4つの制約をつけて初めてスクロールするっぽい
    inView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
    inView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0.0).isActive = true
    inView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0.0).isActive = true
    inView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0.0).isActive = true


    //オレンジのビューのレイアウト
    //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
    topView.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    topView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
    //Y軸
    topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
    //横幅
    topView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 1).isActive = true
    //縦幅
    topView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.1).isActive = true
    //背景色
    topView.backgroundColor = UIColor(hex: self.common.main , alpha: 1)

    //白色のビューのレイアウト
    //(おまじない)
    topViewInner.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    topViewInner.centerXAnchor.constraint(equalTo: topView.centerXAnchor).isActive = true
    //Y軸
    topViewInner.centerYAnchor.constraint(equalTo: topView.centerYAnchor).isActive = true
    //横幅
    topViewInner.widthAnchor.constraint(equalTo: topView.widthAnchor, multiplier: 0.95).isActive = true
    //縦幅
    topViewInner.heightAnchor.constraint(equalTo: topView.heightAnchor, multiplier: 0.6).isActive = true
    //背景色
    topViewInner.backgroundColor = UIColor(hex: self.common.white, alpha: 1)
    //角丸
    topViewInner.layer.cornerRadius = 10
}

//ラベル生成
func labelCreate() {
    //合計日数のラベルを表示
    topViewInner.addSubview(dayLabel)
    //貯金額のラベルを表示
    topViewInner.addSubview(moneyLabel)

    //合計日数のラベルのレイアウト
    //(おまじない)
    dayLabel.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    dayLabel.leftAnchor.constraint(equalTo: topViewInner.leftAnchor, constant: 20.0).isActive = true
    //Y軸
    dayLabel.centerYAnchor.constraint(equalTo: topViewInner.centerYAnchor).isActive = true
    //フォントの設定
    dayLabel.font = UIFont(name: "HiraMaruProN-W4", size: 20)
    //テキストカラー
    dayLabel.textColor = UIColor(hex: common.text , alpha: 1)
    //ラベルのテキスト
    dayLabel.text = "\(whatDay)日目"

    //貯金額のラベルのレイアウト
    //(おまじない)
    moneyLabel.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    moneyLabel.rightAnchor.constraint(equalTo: topViewInner.rightAnchor, constant: -20.0).isActive = true
    //Y軸
    moneyLabel.centerYAnchor.constraint(equalTo: topViewInner.centerYAnchor).isActive = true
    //フォントの設定
    moneyLabel.font = UIFont(name: "HiraMaruProN-W4", size: 20)
    //テキストカラー
    moneyLabel.textColor = UIColor(hex: common.text , alpha: 1)
    //ラベルのテキスト
    moneyLabel.text = "貯金額 \(totalSavings)円"
}
    
//スタックビュー生成
func stackViewCreate() {
    //スタックビュー縦の設定
    //スタックビューの方向を縦に
    stackV.axis = .vertical
    //中のオブジェクトをどこに揃えて配置するか
    stackV.alignment = .fill
    //どう配置するか
    stackV.distribution = .fill
    //オブジェクト同士のスペース
    stackV.spacing = 10
    //おまじない
    stackV.translatesAutoresizingMaskIntoConstraints = false
    //stackVの背景色
    stackV.backgroundColor = UIColor(hex: self.common.background , alpha: 1)//変更
    //stackVを表示
    inView.addSubview(stackV)
    //X軸
    stackV.centerXAnchor.constraint(equalTo: inView.centerXAnchor).isActive = true
    //トップ位置
    stackV.topAnchor.constraint(equalTo: stackV.topAnchor, constant: 0.0).isActive = true
    //横幅
    stackV.widthAnchor.constraint(equalTo: inView.widthAnchor, multiplier: 1.0).isActive = true
    //縦幅
    stackV.heightAnchor.constraint(equalTo: inView.heightAnchor, multiplier: 1.0).isActive = true

    //スタックビュー横を自動生成
    for i in 0 ..< 73 {
        //StackHの生成
        let stackH:UIStackView = UIStackView()
        //スタックビューの方向を横に
        stackH.axis = .horizontal
        //オブジェクト同士のスペース
        stackH.spacing = 10
        //中のオブジェクトをどこに揃えて配置するか
        stackH.alignment = .fill
        //どう配置するか
        stackH.distribution = .fillEqually
        //スタックビュー配列に追加
        stkArray.append(stackH)
        //stackVの中にstackHを格納
        stackV.addArrangedSubview(stkArray[i])
    }

    //ボタンの配置
    //for文のカウンター変数
    var count = 0
    //for文で365個のボタンをどのstackHに入れるか決めている
    for i in 1 ..< 366 {
        //カウントの数に応じてどのstackHに入るか決定する。
        stkArray[count].addArrangedSubview(buttonArray[i - 1] as UIView)
        //ボタンは5列なので5の倍数でcountを一つ増やす。
        if i % 5 == 0 {
            count += 1
        }
    }
}

//ボタン生成#imageLiteral(resourceName: "スクリーンショット 2021-07-09 12.31.23.png")
func btnCreate() {
    //ボタンの生成と設定
    //ボタンにtagを付ける為の変数
    var tagNumber = 1
    //for文でボタンを生成
    for _ in 0...364 {
        //ボタン生成
        let button: UIButton = UIButton(type: .custom)
        //タイトルの色
        button.setTitleColor(UIColor(hex: common.text , alpha: 1), for: UIControl.State())
        //タイトルは数字なのでtagナンバーを指定
        button.setTitle(String(tagNumber), for: UIControl.State())
        //tag設定
        button.tag = tagNumber
        //背景色
        button.backgroundColor = UIColor(hex: common.white , alpha: 1)
        //フォントの設定
        button.titleLabel!.font = UIFont(name: "HiraMaruProN-W4", size: 20)
        //角丸
        button.layer.cornerRadius = 10
        //ボーダーの横幅
        button.layer.borderWidth = 3
        //ボターの色
        button.layer.borderColor = UIColor(hex: common.main , alpha: 1).cgColor
        //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
        button.translatesAutoresizingMaskIntoConstraints = false
        //ボタンの横幅が可変なのでボタンの高さは横幅と同じ長さを指定する事で正方形にしてる。
        button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0).isActive = true
        //変数tagNumberに1追加
        tagNumber += 1
        //ボタン長押し
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressed(_:))
        )
        //長押しを認識する時間の設定
        longPressGesture.minimumPressDuration = 0.01
        //ボタンに長押し機能を付ける
        button.addGestureRecognizer(longPressGesture)
        //ボタンの配列に追加
        buttonArray.append(button)
    }
}

// MARK: - ここからアニメーション関係
//タイマー初期化
var timer: Timer!
//2秒長押ししたかどうか判定する変数
var longTapOK = false
//ボタンのタグを関数の外に出す為の変数
var btnTag = 0

//長押し機能
@objc func longPressed(_ sender: UILongPressGestureRecognizer) {

    if sender.state == .began {
        print("ボタン押した")
        btnTag = sender.view!.tag
        UIView.animate(withDuration: 2) {
            //ボタンを押してる最中のボタンの色を変更
            self.buttonArray[sender.view!.tag - 1].backgroundColor = UIColor(hex: self.common.sub , alpha: 1)
        }
        startTimer()

    } else if sender.state == .ended {
        print("ボタン離した")
        if longTapOK == false {
            //realmの呼び出し
            let realm = try! Realm()

            //if文で条件分岐
            if realm.objects(Btn365.self).filter("tagNum == \(sender.view!.tag)").first != nil {
                print("アラートを出す")
                //アラートのタイトルやメッセージの設定
                let alertController = DOAlertController(title: "解除しますか?", message: "", preferredStyle: .alert)
                //キャンセルアクションの設定
                let cancelAction = DOAlertAction(title: "Cancel", style: .cancel, handler: nil)
                //OKアクションの設定
                let okAction = DOAlertAction(title: "OK", style: .default) { action in
                    print("OKボタンが押された")

                    Btn365.delete(tag: sender.view!.tag)
                    self.whatDay -= 1
                    self.dayLabel.text = "\(self.whatDay)日目"
                    self.totalSavings -= sender.view!.tag
                    self.moneyLabel.text = "貯金額 \(self.totalSavings)円"
                        
                    //アラートでOKを選択した時をボタンの色を白に戻す
                    self.buttonArray[sender.view!.tag - 1].backgroundColor = UIColor(hex: self.common.white, alpha: 1)
                    //アラートでOKを選択した時をテキストの色を白から茶色に戻す
                    self.buttonArray[sender.view!.tag - 1].setTitleColor(UIColor(hex: self.common.text , alpha: 1), for: UIControl.State())
                }
                
                    // アラートのレイアウト
                    //背景色
                    alertController.alertViewBgColor = UIColor.white
                    //角丸
                    alertController.alertView.layer.cornerRadius = 15
                    // タイトルのフォント、
                    alertController.titleFont = UIFont(name: "HiraMaruProN-W4", size: 20)
                    //タイトルの文字色
                    alertController.titleTextColor = UIColor(hex: common.text, alpha: 1)

                    // [.Default]を[.Cancel][.Destructive]に変更すればそれぞれのアクションごとにボタンのカスタマイズが可能
                    //キャンセルボタンのフォント
                    alertController.buttonFont[.cancel] = UIFont(name: "HiraMaruProN-W4", size: 20)
                    //Cancelの背景色
                    alertController.buttonBgColor[.cancel] = UIColor(hex: common.main, alpha: 1)
                    //Cancelを押した時の色※特に変更したくないので背景色と同じ色
                    alertController.buttonBgColorHighlighted[.cancel] = UIColor(hex: common.main, alpha: 1)
                    //OKボタンの背景色
                    alertController.buttonBgColor[.default] =  UIColor(hex: common.sub, alpha: 1)
                    //OKボタンを押した時の色
                    alertController.buttonBgColorHighlighted[.default] =  UIColor(hex: common.sub, alpha: 1)
                
                //キャンセルとOKのアクションを追加
                alertController.addAction(cancelAction)
                alertController.addAction(okAction)
                //アラートを表示
                present(alertController, animated: true, completion: nil)
            } else {
                //色を白に戻す
                UIView.animate(withDuration: 0.1) {
                    //ボタンを長押しして途中で離した場合、ボタンの色を白に戻す。
                    self.buttonArray[sender.view!.tag - 1].backgroundColor = UIColor(hex: self.common.white , alpha: 1) //変更
                }
            }
            //タイマーストップ
            timer.invalidate()
        } else {
            print("ロングタップ成功")
            longTapOK = false
        }
    }
}

//タイマーの設定
func startTimer() {
    timer = Timer.scheduledTimer(
        timeInterval: 2, //タイマーの間隔を設定
        target: self,
        selector: #selector(self.timerCounter), //メソッドの設定
        userInfo: nil,
        repeats: false) //リピートするかどうか
}
    
//タイマーで実行される処理
@objc func timerCounter() {
    //ロングタップ成功
    longTapOK = true
    //ぽよよんアニメーションの実行
    animateView(topViewInner)
    //バイブさせる
    AudioServicesPlaySystemSound(1102)
    //ラベルの更新
    updateLabel()
    //RealmDBへ登録
    let a = Btn365.create()
    a.tagNum = btnTag
    a.save()
//アクティブになった時にボタンのテキストの色を白に
self.buttonArray[btnTag - 1].setTitleColor(UIColor(hex: self.common.white , alpha: 1), for: UIControl.State())
}
    
//ラベルの値を更新する(長押し認識してから2秒後に実行される)
func updateLabel() {
    //貯金額を更新
    totalSavings += btnTag
    //合計日数を更新
    whatDay += 1
    //貯金額ラベルを更新
    moneyLabel.text = "貯金額 \(totalSavings)円"
    //合計日数ラベルを更新
    dayLabel.text = "\(whatDay)日目"
}
    
//ぽよよんアニメーション
func animateView(_ viewToAnimate:UIView) {
    UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseIn, animations: {
        viewToAnimate.transform = CGAffineTransform(scaleX: 1.08, y: 1.08)
    }) { (_) in
        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 10, options: .curveEaseOut, animations: {
            viewToAnimate.transform = .identity

        }, completion: nil)
    }
}
}

MenuViewController.swift

import RealmSwift
import StoreKit

class MenuViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    

//Commonクラスのインスタンス生成
let common = Common()
//Cancelボタン
var cancelBtn: UIBarButtonItem!
//テーブルビューの変数
var tableView: UITableView?
//セル用の配列
let items = ["貯金忘れ防止アラーム", "使い方", "シェア", "評価", "データリセット"]
let icons = ["menuIcon-1", "menuIcon-2", "menuIcon-3", "menuIcon-4", "menuIcon-5"]
//Realm通知
var token : NotificationToken?

override func viewDidLoad() {
    super.viewDidLoad()
    
//Realmのデータが更新されたら検知する
let realm = try! Realm()
token = realm.observe({ (notification:Realm.Notification, realm) in
  print("realm is updated")
    //アラートの表示
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        let alertController = self.common.originalAlert(title: "削除しました", message: "")
        self.present(alertController, animated: true, completion: nil)
    }
})

//ナビゲーションコントローラーまわり
//タイトル
self.title = "メニュー"
//背景色
self.navigationController?.navigationBar.barTintColor = UIColor(hex: self.common.main , alpha: 1)
//セーフエリアとの境目の線を消す
self.navigationController?.navigationBar.shadowImage = UIImage()
//フォントの設定
self.navigationController?.navigationBar.titleTextAttributes
    = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "HiraMaruProN-W4", size: 20)!]
//Cancelボタンを追加
cancelBtn = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(self.cancelBtnTapped))
cancelBtn.tintColor = UIColor(hex: self.common.white , alpha: 1)
self.navigationItem.leftBarButtonItem = cancelBtn
    
//テーブルビューの設定
self.tableView = {
    let tableView = UITableView(frame: self.view.bounds, style: .plain)
    tableView.autoresizingMask = [
      .flexibleWidth,
      .flexibleHeight
    ]

    tableView.delegate = self
    tableView.dataSource = self

    self.view.addSubview(tableView)

    tableView.register(MenuTableViewCell.self, forCellReuseIdentifier: "Cell")
    
    return tableView

  }()
}

//Cancelボタンのメソッド
@objc func cancelBtnTapped() {
    //前の画面に戻る
    dismiss(animated: true, completion: nil)
}

    
//テーブルビューまわり
//テーブルビューのセクションの数を設定
func numberOfSections(in tableView: UITableView) -> Int {
  return 1
}
//テーブルビューのセルの数を設定
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  //配列itemsの数になるように設定
  return self.items.count
}

//セルの設定
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //カスタムをセルを使えるように設定
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! MenuTableViewCell
    //ラベルのテキストとアイコン画像のファイル名を設定
    cell.setCell(item: self.items[indexPath.row], iconName: icons[indexPath.row])
    //セルの右側に<を付ける
    cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
    //セル選択時に背景色を変更しない
    cell.selectionStyle = UITableViewCell.SelectionStyle.none
    return cell
}
    
//セルを選択した時の設定
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  print("Selected! \(self.items[indexPath.row])")
    switch indexPath.row {
    case 0:
        print("アラーム設定画面へ")
    case 1:
        print("ウォークスルー画面へ")
    case 2:
        print("シェア")
        share()
    case 3:
        print("評価")
        //レビューダイアログを表示
        if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
            SKStoreReviewController.requestReview(in: scene)
        }
    case 4:
        print("データリセット")
        deleteAlert()

    default:
        break
        }
    }

func share() {
    //URLは自分のアプリのappstoreURLを設定する(今回はもしも貯金箱のURL)
    let shareUrl = ShareItem(URL(string: "https://apps.apple.com/jp/app/%E3%82%82%E3%81%97%E3%82%82%E8%B2%AF%E9%87%91%E7%AE%B1/id1553026256")!)
    let activityVC = UIActivityViewController(activityItems: [shareUrl], applicationActivities: nil)
    //ipadの場合の処理
    if UIDevice.current.userInterfaceIdiom == .pad {
        let screenSize = UIScreen.main.bounds
        activityVC.popoverPresentationController?.sourceView = self.view
        activityVC.popoverPresentationController?.sourceRect = CGRect(x:screenSize.size.width/2, y: screenSize.size.height-200, width: 0, height: 0)
    }
    present(activityVC, animated: true, completion: nil)
}

func deleteAlert() {
    //タイトルとメッセージの設定
    let alertController = DOAlertController(title: "本当に削除しますか?", message: "削除すると元には戻せません!", preferredStyle: .alert)
    //キャンセルボタンの設定
    let cancelAction = DOAlertAction(title: "Cancel", style: .cancel, handler: nil)
    //OKボタンの設定
    let okAction = DOAlertAction(title: "OK", style: .default) { action in
        //メインビューコントローラー取得
        let nc = self.presentingViewController as! UINavigationController
        let vcNum = nc.viewControllers.count
        let firstVC = nc.viewControllers[vcNum - 1] as! MainViewController
        //先に色とか変更しちゃう
        firstVC.deleteAlertBack()
        //realmDBを全て削除
        let realm = try! Realm()
        try! realm.write {
          realm.deleteAll()
        }
    }

    // アラートビューの背景色
    alertController.alertViewBgColor = UIColor.white
    alertController.alertView.layer.cornerRadius = 15
    // タイトルのフォント、文字色
    alertController.titleFont = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.titleTextColor = UIColor(hex: "8a6b52", alpha: 1)
    alertController.messageFont = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.messageTextColor = UIColor.red
    //キャンセルボタンの設定
    alertController.buttonFont[.cancel] = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.buttonBgColor[.cancel] = UIColor(hex: common.main, alpha: 1)
    alertController.buttonBgColorHighlighted[.cancel] = UIColor(hex: common.main, alpha: 1)
    //OKボタンの設定
    alertController.buttonFont[.default] = UIFont(name: "HiraMaruProN-W4", size: 17)
    alertController.buttonBgColor[.default] = UIColor.red
    alertController.buttonBgColorHighlighted[.default] = UIColor.red

    // アラートコントローラにアクションを追加
    alertController.addAction(cancelAction)
    alertController.addAction(okAction)

    // 表示
    present(alertController, animated: true, completion: nil)
}

}

class ShareItem<T>: NSObject, UIActivityItemSource {

    private let item: T

    init(_ item: T) {
        self.item = item
    }

    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return item
    }

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return activityViewControllerPlaceholderItem(activityViewController)
    }
}

Common.swift

import Foundation
import UIKit

class Common: NSObject {
//カラー指定
let background = "faf2ed"
let main = "eeaa7b"
let sub = "66b9bf"
let text = "8a6b52"
let Overlay = "000000"
let white = "ffffff"

func originalAlert(title: String, message: String) -> DOAlertController {
    // アラートコントローラ: タイトル、メッセージ、アラートスタイル(Alert/ActionSheet)を設定
    let alertController = DOAlertController(title: title, message: message, preferredStyle: .alert)
    
    // アクション: ボタンの文字、ボタンスタイル(Default/Cancel/Destructive)、ボタンを押した時の処理を設定
    let cancelAction = DOAlertAction(title: "OK", style: .cancel, handler: nil)
    
    // アラートビューの背景色
    alertController.alertViewBgColor = UIColor.white
    alertController.alertView.layer.cornerRadius = 15
    // タイトルのフォント、文字色
    alertController.titleFont = UIFont(name: "HiraMaruProN-W4", size: 14)
    alertController.titleTextColor = UIColor(hex: text, alpha: 1)
    
    alertController.messageTextColor = UIColor(hex: text, alpha: 1)
    alertController.messageFont = UIFont(name: "HiraMaruProN-W4", size: 14)
    // ボタンのフォント、文字色、背景色(通常時/ハイライト時)
    // [.Default]を[.Cancel][.Destructive]に変更すればそれぞれのアクションごとにボタンのカスタマイズが可能
    alertController.buttonFont[.cancel] = UIFont(name: "HiraMaruProN-W4", size: 17)
    //            alertController.buttonTextColor[.cancel] = UIColor(hex: "66b9bf", alpha: 1)
    alertController.buttonBgColor[.cancel] = UIColor(hex: main, alpha: 1)
    alertController.buttonBgColorHighlighted[.cancel] = UIColor(hex: main, alpha: 1)
    
    // アラートコントローラにアクションを追加
    alertController.addAction(cancelAction)

    return alertController
}
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

アプリ