テーマカラー設定をアプリに保存する

ソースコード:MyColorMemoAppSwiftUI

//

import SwiftUI

enum MyColorType: Int, CaseIterable {
  case base // #FFFFFF
  case orange // #F8C165
  case red // #D24141
  case blue // #4187FA
  case pink // #F064B9
  case green // #50AA41
  case purple // #965AD2
  
  var color: Color {
    switch self {
    case .base: return .white
    case .orange: return Color.rgbo(red: 248, green: 193, blue: 101, opacity: 1)
    case .red: return Color.rgbo(red: 210, green: 65, blue: 65, opacity: 1)
    case .blue: return Color.rgbo(red: 65, green: 135, blue: 250, opacity: 1)
    case .pink: return Color.rgbo(red: 240, green: 100, blue: 185, opacity: 1)
    case .green: return Color.rgbo(red: 80, green: 170, blue: 65, opacity: 1)
    case .purple: return Color.rgbo(red: 150, green: 90, blue: 210, opacity: 1)
    }
  }
  
  var title: String {
    switch self {
    case .base: return "デフォルト"
    case .orange: return "オレンジ"
    case .red: return "レッド"
    case .blue: return "ブルー"
    case .pink: return "ピンク"
    case .green: return "グリーン"
    case .purple: return "パープル"
    }
  }
  
}
extension Color {
  static func rgbo(red: Int, green: Int, blue: Int, opacity: CGFloat = 1) -> Color {
    return Color(red: CGFloat(red) / 255, green: CGFloat(green) / 255, blue: CGFloat(blue) / 255, opacity: opacity)
  }
}

//

import SwiftUI

class MyColor: ObservableObject {
  let themeColorTypeKey = "themeColorType"
  @Published var color: Color = MyColorType.base.color
  
  init() {
    self.color = themeColor
  }
  
  var themeColor: Color {
    let savedTypeInt = UserDefaults.standard.integer(forKey: themeColorTypeKey)
    return MyColorType(rawValue: savedTypeInt)?.color ?? MyColorType.base.color
  }
  
  func changeAndSaveThemeColor(type: MyColorType) {
    color = type.color
    UserDefaults.standard.setValue(type.rawValue, forKey: themeColorTypeKey)
  }
}

//

import SwiftUI
import RealmSwift

struct HomeView: View {
  @ObservedResults(MemoDataModel.self) var memoDataList
  @State var isShowColorSetting = false
  @EnvironmentObject var myColor: MyColor
  
  var body: some View {
    NavigationStack {
      VStack {
        memoList
        // Spacerを下に入れることで、メモ一覧を上に詰めるように表示させる
        Spacer()
      }
      .toolbarBackground(myColor.color, for: .navigationBar)
      .toolbarBackground(.visible, for: .navigationBar)
      // NavigationBarに設置するボタンなどを定義
      .toolbar {
        // 左上:テーマカラー設定
        ToolbarItem(placement: .navigationBarLeading) {
          colorSettingButton
        }
        // 右上:新規メモ作成
        ToolbarItem(placement: .navigationBarTrailing) {
          memoCreateLinkButton
        }
      }
    }
    
  }
  
  /// メモ一覧.
  var memoList: some View {
    List {
      ForEach(memoDataList, id: \.self) { memo in
        // NavigationLinkは画面遷移を行うViewです
        // タップでdestinationに記載したViewへNavigation遷移
        NavigationLink(
          // 画面遷移する際にタップしたセルのMemoDataを渡す
          destination:
            MemoDetailView(memoData: memo)
        ) {
          memoCell(memo)
        }
      }
      .onDelete(perform: delete)
    }
    .listStyle(.plain)
  }
  
  /// カラー設定ボタン.
  var colorSettingButton: some View {
    Button(
      action: {
        isShowColorSetting = true
      }, label: {
        Image(.colorSettingIcon)
      }
    )
    .confirmationDialog("テーマカラーを選択してください", isPresented: $isShowColorSetting) {
      ForEach(MyColorType.allCases, id: \.self) { type in
        Button(
          action: {
            myColor.changeAndSaveThemeColor(type: type)
          }, label: {
            Text(type.title)
          }
        )
      }
      Button("キャンセル", role: .cancel) {}
    }
  }
  
  /// メモ作成ボタン.
  var memoCreateLinkButton: some View {
    // NavigationLinkはTextだけでなく画像やViewでも設定できる
    NavigationLink(
      // onAppearで生成した新しいMemoDataを渡す
      destination:
        MemoDetailView(memoData: MemoDataModel())
    ) {
      Image(systemName: "plus")
    }
  }
}

// MARK: View Components
extension HomeView {
    /// メモ一覧に表示するセル.
    func memoCell(_ memo: MemoDataModel) -> some View {
        VStack(alignment: .leading) {
            // メモのテキスト
            Text(memo.text)
                .font(.body)
            // メモの作成・編集日時
            Text(formatDate.string(from: memo.recordDate))
                .font(.footnote)
        }
    }
}

extension HomeView {
    // 表示形式を変更した日付
    var formatDate: DateFormatter {
        let formatter = DateFormatter()
        // Apple が推奨する固定フォーマット用ロケール
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(identifier: "UTC")
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
        return formatter
    }
}

// MARK: Methods
extension HomeView {
  /// リストからメモを削除する処理(Realm オブジェクトを削除).
  func delete(at offsets: IndexSet) {
    // map + firstで削除対象のオブジェクトを取得
    if let objectToDelete = offsets
        // インデックスを使って、対応するメモデータを取り出す
      .map({ memoDataList[$0] })
        // 今回は最初の1件だけを削除対象にする
      .first {
      // removeでリストからメモデータを削除
      self.$memoDataList.remove(objectToDelete)
    }
  }
}
      
#Preview {
  @Previewable @StateObject var myColor = MyColor()
    HomeView()
    .environmentObject(myColor)
}

  • ユーザー名:
  • 受講プラン:
  • 完了ステータス:未完了
cta_img

受講申し込みはこちらから

まずは受講用アカウントの作成からスタート。
iOSアカデミアの受講に必要な各種情報を記載した、ご案内メールをお届けします。

受講申し込み