20211015のSwiftに関する記事は4件です。

特定の時間のみ指定可能なTimePickerを作る

完成形はこんな感じです 今回は00と30のみ指定可能なTimePickerを作成します minuteIntervalを指定する事で選択を制限することができますがUXが悪いのでこっちがおすすめです 説明することもないのでコードのみ載せておきます UIKit class ViewController: UIViewController { let timePicker: UIDatePicker = { let dp = UIDatePicker() dp.datePickerMode = UIDatePicker.Mode.time dp.timeZone = NSTimeZone.local dp.preferredDatePickerStyle = .wheels dp.locale = Locale.init(identifier: "Japanese") dp.addTarget(self, action: #selector(timeChange), for: .valueChanged) return dp }() override func viewDidLoad() { super.viewDidLoad() timeChange() timePicker.backgroundColor = .white timePicker.tintColor = UIColor.black timePicker.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(timePicker) timePicker.clipsToBounds = true timePicker.layer.cornerRadius = 10.0 } @objc func timeChange() { let minutes = DateFormatter() minutes.timeZone = .current minutes.timeStyle = .short minutes.dateStyle = .none minutes.locale = NSLocale.system minutes.dateFormat = "m" let SelectTime = Calendar.current.date(byAdding: .hour, value: -3, to: timePicker.date)! let Minutes = Int(minutes.string(from: SelectTime))! if 0 < Minutes && Minutes < 30 { let modifiedDate = Calendar.current.date(byAdding: .minute, value: 30 - Minutes, to: timePicker.date)! timePicker.date = modifiedDate } if 30 < Minutes && Minutes < 60 { let modifiedDate = Calendar.current.date(byAdding: .minute, value: 60 - Minutes, to: timePicker.date)! timePicker.date = modifiedDate } } } SwiftUI struct ContentView: View { @State private var TIME = Date() var body: some View { VStack { DatePicker("", selection: $TIME, displayedComponents: .hourAndMinute) .frame(width: 300, height: 60) .datePickerStyle(WheelDatePickerStyle()) .labelsHidden() .cornerRadius(10) .onChange(of: TIME) { i in ChangeTime() } } .onAppear() { ChangeTime() } } func timeM() -> String { let dateFormatter = DateFormatter() dateFormatter.timeZone = .current dateFormatter.timeStyle = .short dateFormatter.dateStyle = .none dateFormatter.locale = NSLocale.system dateFormatter.dateFormat = "m" let mString = dateFormatter.string(from: TIME) return mString } func ChangeTime() { let mString = timeM() let m = Int(mString)! if 0 < m && m < 30 { let NextTime = Calendar.current.date(byAdding: .minute, value: 30 - m, to: TIME)! TIME = NextTime print(TIME) } else { if 30 < m && m < 60 { let NextTime = Calendar.current.date(byAdding: .minute, value: 60 - m, to: TIME)! TIME = NextTime print(TIME) } } } } UIKitは全然理解してないのでおかしい部分があるかもです 思った通りに動いてるので良しとしてください笑
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

入力した文字数によってUITextFieldの見た目などに反映

今回の内容 コード 全てコードで書いてますので、長いですがコピペで試せますので良ければご覧ください。 import UIKit class ViewController: UIViewController { let textfield01 = UITextField() var surveillanceLabel01 = UILabel() let textfield02 = UITextField() var surveillanceLabel02 = UILabel() let textfield03 = UITextField() var surveillanceLabel03 = UILabel() let button01 = UIButton() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .tertiarySystemGroupedBackground //textfield01 textfield01.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 6.7, width: view.frame.width - (view.frame.maxX / 5), height: 40) textfield01.placeholder = "3文字以上入力して下さい" textfield01.layer.cornerRadius = 10.0 textfield01.layer.borderWidth = 3.0 textfield01.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield01.leftViewMode = .always textfield01.layer.borderColor = UIColor.black.cgColor textfield01.backgroundColor = .white textfield01.addTarget(self, action: #selector(textfield01Surveillance), for: .editingChanged) view.addSubview(textfield01) surveillanceLabel01.frame = CGRect(x: textfield01.frame.minX + 3, y: textfield01.frame.maxY, width: textfield01.frame.width, height: textfield01.frame.height / 2.5) surveillanceLabel01.font = UIFont.boldSystemFont(ofSize: 13) view.addSubview(surveillanceLabel01) //textfield02 textfield02.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 3.76, width: view.frame.width - (view.frame.maxX / 5), height: 40) textfield02.placeholder = "5文字以上入力して下さい" textfield02.layer.cornerRadius = 10.0 textfield02.layer.borderWidth = 3.0 textfield02.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield02.leftViewMode = .always textfield02.layer.borderColor = UIColor.black.cgColor textfield02.backgroundColor = .white textfield02.addTarget(self, action: #selector(textfield02Surveillance), for: .editingChanged) view.addSubview(textfield02) surveillanceLabel02.frame = CGRect(x: textfield02.frame.minX + 3, y: textfield02.frame.maxY, width: textfield02.frame.width, height: textfield02.frame.height / 2.5) surveillanceLabel02.font = UIFont.boldSystemFont(ofSize: 13) view.addSubview(surveillanceLabel02) //textfield03 textfield03.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 2.61, width: view.frame.width - (view.frame.maxX / 5), height: 40) textfield03.placeholder = "8文字以上入力して下さい" textfield03.layer.cornerRadius = 10.0 textfield03.layer.borderWidth = 3.0 textfield03.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0)) textfield03.leftViewMode = .always textfield03.layer.borderColor = UIColor.black.cgColor textfield03.backgroundColor = .white textfield03.addTarget(self, action: #selector(textfield03Surveillance), for: .editingChanged) view.addSubview(textfield03) surveillanceLabel03.frame = CGRect(x: textfield03.frame.minX + 3, y: textfield03.frame.maxY, width: textfield03.frame.width, height: textfield03.frame.height / 2.5) surveillanceLabel03.font = UIFont.boldSystemFont(ofSize: 13) view.addSubview(surveillanceLabel03) //button01 button01.frame = CGRect(x: view.frame.maxX / 10, y: view.frame.maxY / 1.79, width: view.frame.width - (view.frame.width / 5), height: 45) button01.setTitle("NotStart", for: .normal) button01.titleLabel?.textColor = .white button01.titleLabel?.font = UIFont.boldSystemFont(ofSize: 25) button01.backgroundColor = .systemRed button01.layer.cornerRadius = 20.0 button01.layer.shadowOffset = CGSize(width: 5, height: 5) button01.layer.shadowOpacity = 0.8 button01.layer.shadowRadius = 5.0 button01.layer.masksToBounds = true button01.isEnabled = false button01.addTarget(self, action: #selector(showIndicator), for: .touchDown) view.addSubview(button01) } @objc func textfield01Surveillance(sender:UITextField){ switch sender.text!.count >= 3{ case true: sender.layer.borderColor = UIColor.systemGreen.cgColor surveillanceLabel01.text = "入力完了" surveillanceLabel01.textColor = .systemGreen if sender.text!.count >= 3 && textfield02.text!.count >= 5 && textfield03.text!.count >= 8{ button01.layer.masksToBounds = false button01.setTitle("AppStart", for: .normal) button01.backgroundColor = .systemGreen button01.isEnabled = true } case false: sender.layer.borderColor = UIColor.systemRed.cgColor surveillanceLabel01.textColor = .systemRed surveillanceLabel01.text = "注意:3文字以上入力して下さい" button01.setTitle("NotStart", for: .normal) button01.backgroundColor = .systemRed button01.layer.masksToBounds = true button01.isEnabled = false } } @objc func textfield02Surveillance(sender:UITextField){ switch sender.text!.count >= 5{ case true: sender.layer.borderColor = UIColor.systemGreen.cgColor surveillanceLabel02.text = "入力完了" surveillanceLabel02.textColor = .systemGreen if textfield01.text!.count >= 3 && sender.text!.count >= 5 && textfield03.text!.count >= 8{ button01.layer.masksToBounds = false button01.setTitle("AppStart", for: .normal) button01.backgroundColor = .systemGreen button01.isEnabled = true } case false: sender.layer.borderColor = UIColor.systemRed.cgColor surveillanceLabel02.textColor = .systemRed surveillanceLabel02.text = "注意:5文字以上入力して下さい" button01.setTitle("NotStart", for: .normal) button01.backgroundColor = .systemRed button01.layer.masksToBounds = true button01.isEnabled = false } } @objc func textfield03Surveillance(sender:UITextField){ switch sender.text!.count >= 8{ case true: sender.layer.borderColor = UIColor.systemGreen.cgColor surveillanceLabel03.text = "入力完了" surveillanceLabel03.textColor = .systemGreen if textfield01.text!.count >= 3 && textfield02.text!.count >= 5 && sender.text!.count >= 8{ button01.layer.masksToBounds = false button01.setTitle("AppStart", for: .normal) button01.backgroundColor = .systemGreen button01.isEnabled = true } case false: sender.layer.borderColor = UIColor.systemRed.cgColor surveillanceLabel03.textColor = .systemRed surveillanceLabel03.text = "注意:8文字以上入力して下さい" button01.setTitle("NotStart", for: .normal) button01.backgroundColor = .systemRed button01.layer.masksToBounds = true button01.isEnabled = false } } @objc func showIndicator(sender:UIButton){ textfield01.isEnabled = false textfield02.isEnabled = false textfield03.isEnabled = false sender.setTitle("", for: .normal) UIButton.animate(withDuration: 0.5, delay: 0, options: .allowAnimatedContent, animations: { sender.frame = CGRect(x: self.view.center.x - (sender.frame.size.width / 7) / 2, y: sender.frame.origin.y, width: sender.frame.size.width / 7, height: sender.frame.size.height) sender.layer.cornerRadius = 23.0 }, completion: nil) let indicator = UIActivityIndicatorView() indicator.frame.origin = CGPoint(x: sender.center.x, y: sender.center.y) indicator.color = .white view.addSubview(indicator) indicator.startAnimating() DispatchQueue.main.asyncAfter(deadline: .now() + 3) { indicator.stopAnimating() UIButton.animate(withDuration: 0.5, delay: 0, options: .allowAnimatedContent, animations: { sender.frame = CGRect(x: self.view.frame.minX + 20, y: sender.frame.origin.y, width: self.view.frame.maxX - 40, height: sender.frame.size.height) sender.layer.cornerRadius = 20.0 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { sender.setTitle("AppStart", for: .normal) self.textfield01.isEnabled = true self.textfield02.isEnabled = true self.textfield03.isEnabled = true } }, completion: nil) } } } 終わり ご指摘、ご質問などありましたら、コメントまでお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SwiftUI】インジケーター

ソースコード Viewのレイアウトは参考文献より引用。 import SwiftUI // trueならばViewを表示、falseならばEmptyView() extension View { @ViewBuilder func isHidden(_ hidden: Bool) -> some View { if hidden { EmptyView() } else { self } } } struct LoadingIndicatorView: View { let isLoading: Bool @State private var isAnimating = false private let animation = Animation.linear(duration: 1).repeatForever(autoreverses: false) init(_ isLoading:Bool){ self.isLoading = isLoading } var body: some View { GeometryReader { geometry in ZStack { // ①Loading中に画面をタップできないようにするためのほぼ透明なLayer Color(.black) .opacity(0.01) .frame(width: geometry.size.width, height: geometry.size.height) .edgesIgnoringSafeArea(.all) .disabled(self.isLoading) Circle() .trim(from: 0, to: 0.6) .stroke(AngularGradient(gradient: Gradient(colors: [.gray, .white]), center: .center), style: StrokeStyle( lineWidth: 8, lineCap: .round, dash: [0.1, 16], dashPhase: 8)) .frame(width: 48, height: 48) .rotationEffect(.degrees(self.isAnimating ? 360 : 0)) .onAppear() { withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) { self.isAnimating = true } } .onDisappear() { self.isAnimating = false } } .isHidden(!self.isLoading) } } } struct LoadingIndicatorView_Previews: PreviewProvider { static var previews: some View { LoadingIndicatorView(true) } } 補足 View表示の切り替えはextensionで拡張したViewプロパティを使用。(標準Viewプロパティ.hidden()は引数を持たないため表示・非表示の切り替えが煩わしい) 最適化を考慮し、self.hidden()の代わりにEmptyView()を返している。 参考文献 この記事は以下の情報を参考にして執筆しました。 SwfitUIで通信中にIndicatorを表示できるようにする。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

associatedtype swift

謎のワードだったassociatedtypeを調べてみた。  associatedtypeキーワードでプロトコルの連想型を定義することができる。 通常であればプロトコルを宣言した際に引数や戻り値の型を指定する必要があると思うが、associatedTypeを指定するとデリゲートした際に 型を指定することができる。 連想型を使用指定していけば、より抽象的なプロトコルを定義できる。 書き方 protocol プロトコル {  associatedType 連想型名  var プロパティ名:連想型  func メソッド名(引数:連想型名)  func メソッド名()→連想型名 } 連想型の実際の型は、プロトコルにdelegateする型ごとに指定できる。 準拠側 1 typeliasで指定 typelias 連想型名 = Int 2 実装から自動的に決めることもできる var プロパティ名 :Int func メソッド名(引数:Int)  func メソッド名()→Int {return 3} 3.型を定義せずに再度ネストする形で要求を満たすことも可能である struct 連想型名() var プロパティ名 :連想型名  func (引数:連想型名){} func ()→連想型名{}  型の制約  連想型とはいえ準拠しなくてはならないプロトコル、継承していて欲しいスーパークラスがある場合は下記のように指定する 指定したプロトコルに準拠、もしくはスーパークラスを継承していない場合はコンパイルエラーになってしまう。  associatedType 連想型名 :プロトコルやスーパークラス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む