【SwiftUI】Search TextField を作る

これ。

NavigationStack なしでも、

自在にどこでも置きたいのだが。

👉 SwiftUIでSearchBarが使いたいので自作する | DevelopersIO hatena-bookmark

私も作ってみます、

リストが表示されるやつ。

とりあえず、横に並べて開始します。


HStack {
  Button {
  } label : {
    Image(systemName: "magnifyingglass")
  }

  TextField("Search", text: .constant(""))

  Button {
  } label : {
    Image(systemName: "xmark.circle.fill")
  }
}

 

🧑🏻‍💻 フォーカスの位置の付け替え

デフォルトの TextField のフォーカスの状態を取得して、

エフェクトは無効化する。


TextField("Search", text: .constant(""))
  .focused($focused) 
  .textFieldStyle(.plain)

それらの外にある HStack の border をフォーカス状態によって色を切り替える。


}  // HStack
.border(focused ? Color.accentColor : .gray, width: 1)

 

🧑🏻‍💻 リストのオーバーラップ表示

フォーカスの状態によって、

選択肢のリスト表示を overlay します。

offset 値は入力エリアの高さです。


}  // HStack
.border(focused ? Color.accentColor : .gray, width: 1)
.overlay {
  if focused {
    VStack {
      ForEach(0...3, id: \.self) { i in
        HStack {
          Text("\(i)")
            Spacer()
        }
      }
    }
    .background()
    .offset(y: -45)
  }
}

あとは、レイアウトを調整していけば OK!



 

🧑🏻‍💻 フォーカスのアニメーション

よく見てみると、フォーカスってアニメーションだったんですか !

フォーカス処理部分をバックグラウンドでアニメ化しました。


.background {
  RoundedRectangle(cornerRadius: 8)
    .stroke(.gray, lineWidth: 0.5)
  RoundedRectangle(cornerRadius: 8)
    .stroke(
      focused ? .orange : .clear,
      lineWidth: focused ? 5 : 16
    )
}
.animation(.default, value: focused)

 

🧑🏻‍💻 まとめ



もうググってもしんどいですね。

ChatGPT や copilot などのAI系でも時間がかかるし。

👉 【SwiftUI】#Preview with @Binding arguments hatena-bookmark



【Swift】公式サンプル Logger の使い方


print("debug: \(value)")

とかではつらいのかな。

と思いつつ抽出して使ってみる。

👉 Code search results hatena-bookmark


import OSLog
private let logger = Logger(subsystem: "BackyardBirds", category: "BackyardBirdsPassStatus")


logger.log("""
  Processing transaction ID \(unsafeTransaction.id) for \
  \(unsafeTransaction.productID)
""")


logger.debug("""
  Transaction ID \(t.id) for \(t.productID) is verified
""")


logger.error("""
  Transaction ID \(t.id) for \(t.productID) is unverified: \(error)
""")


logger.info("Providing updated status to data generation")

出力レベルがあるんですね。

出力は、


2023-09-16 18:26:11.842691+0900 Develop[99999:999999] [Standard] Debug: Uhooi
2023-09-16 18:26:11.842722+0900 Develop[99999:999999] [Standard] Info: Uhooi
2023-09-16 18:26:11.842766+0900 Develop[99999:999999] [Standard] Notice: Uhooi
2023-09-16 18:26:11.842811+0900 Develop[99999:999999] [Standard] Error: Uhooi
2023-09-16 18:26:11.842858+0900 Develop[99999:999999] [Standard] Fault: Uhooi

{Timestamp} {Library}[{PID}:{TID}] [{Category}] {Message} の形式で出力されています。

👉 os.Loggerの説明と使い方(Swift) #Swift - Qiita hatena-bookmark

なるほど。

 

■ やってみる


import OSLog
private let logger = Logger(subsystem: "subsystem", category: "category")

// ... 

  static func create(modelContainer: ModelContainer) {
    
    logger.debug("debug Creating service instance.")
    logger.trace("trace Creating service instance.")
    logger.info("infoCreating service instance.")
    logger.notice("notice Creating service instance.")
    logger.error("error Creating service instance.")
    logger.warning("warning Creating service instance.")
    logger.fault("fault Creating service instance.")
    logger.critical("critical Creating service instance.")

    shared = SoundDataService(modelContainer: modelContainer)
  }


debug Creating service instance.
trace Creating service instance.
infoCreating service instance.
notice Creating service instance.
error Creating service instance.
warning Creating service instance.
fault Creating service instance.
critical Creating service instance.

あれ、タイムスタンプ的なのデフォルトで出ないのか。

subsystem とか category とかも何の意味があるのか。

print() で良くね?

なんなのこれ。

あ、これか。

extension 化しとくのが楽かもしれません。


extension OSLog {
  static let ui = Logger(subsystem: "com.satoriku.OSLog", category: "ui")
  static let network = Logger(subsystem: "com.satoriku.OSLog", category: "network")
  static let viewCycle = Logger(subsystem: "com.satoriku.OSLog", category: "viewcycle")
}

👉 【Xcode/Swift】OSLogを使ってアプリログを出力する方法(ロギング) - iOS-Docs hatena-bookmark


import Foundation
import os

extension Logger {
    private static var subsystem = Bundle.main.bundleIdentifier!
    static let segue = Logger(subsystem: subsystem, category: "segue")
    static let note = Logger(subsystem: subsystem, category: "note")
    static let flashcard = Logger(subsystem: subsystem, category: "flashcard")
    static let deck = Logger(subsystem: subsystem, category: "deck")
    static let settings = Logger(subsystem: subsystem, category: "settings")
    static let option = Logger(subsystem: subsystem, category: "option")
}

👉 Flashcard-Adder/Flashcard Adder/Logger.swift at bfa5f3526fba48f5c6596f92d7648e4137fa60c9 · Nonameentered/Flashcard-Adder hatena-bookmark
👉 OSLog and Unified logging as recommended by Apple - SwiftLee hatena-bookmark

👉 Logger | Apple Developer Documentation hatena-bookmark


【iOS】System Sound Wheel Picker

ひとつの View だけで

その端末の組み込みのシステム音を

確認できたらいいかも、

ということで。

GIF って音声出ませんでした ?



以下、音が出てます。



確認の範囲として、

SystemSoundID は 1 から 4000 まで。

実際に音を並列で鳴らして 0.0025 秒以下の音は無視してます。

非同期の処理はここでも難しい印象を受けます。

👉 【Swift】SystemSoundID 一覧がないのですが hatena-bookmark