Xcode 10.3
ios 12.4
swift5
ios 12.4
swift5
完成品
UI
コード
WorldClockVC
import UIKit class WorldClockVC: UIViewController ,UITableViewDelegate,UITableViewDataSource{ var selectTimezones = [String]() var userDefaults = UserDefaults.standard var timer = Timer() @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() loadTimeZones() tableView.register(UINib(nibName: "WorldClockCell", bundle: nil), forCellReuseIdentifier: "WorldClockCell") self.navigationItem.setLeftBarButton(self.editButtonItem, animated: true) } func loadTimeZones(){ if let getTimeZones = userDefaults.object(forKey: "TimeZones") as? [String]{ selectTimezones = getTimeZones } } func saveTimeZones(){ userDefaults.set(selectTimezones, forKey: "TimeZones") userDefaults.synchronize() } override func setEditing(_ editing: Bool, animated: Bool) { super.setEditing(editing, animated: animated) tableView.setEditing(editing, animated: animated) } func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { let sourceCellItem = selectTimezones[sourceIndexPath.row] guard let indexPath = selectTimezones.firstIndex(of: sourceCellItem) else { return } selectTimezones.remove(at: indexPath) selectTimezones.insert(sourceCellItem, at: destinationIndexPath.row) saveTimeZones() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return selectTimezones.count } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 60 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "WorldClockCell") as! WorldClockCell cell.setCity(name: selectTimezones[indexPath.row]) return cell } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { selectTimezones.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) saveTimeZones() } } func timeZone(city:String) -> String{ let formatter = DateFormatter() formatter.dateFormat = "HH:mm" let timeZoneIdentifiers = TimeZone.knownTimeZoneIdentifiers for identifier in timeZoneIdentifiers { if identifier.contains(city){ formatter.timeZone = TimeZone(identifier: identifier) } } return formatter.string(from: Date()) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let nvc = segue.destination as? UINavigationController else {return} guard let vc = nvc.topViewController as? WorldClockSelectVC else {return} vc.delegate = self } } extension WorldClockVC:WorldClockSelectVCDelegte{ func worldClockSelect(cancel: WorldClockSelectVC) { self.setEditing(false, animated: false) } func worldClockSelect(selectedWorldClock: WorldClockSelectVC, selected: String) { if !selectTimezones.contains(selected){ selectTimezones.append(selected) } tableView.reloadData() saveTimeZones() } }
WorldClockCell
import UIKit class WorldClockCell: UITableViewCell { @IBOutlet weak var timeLabel: UILabel! @IBOutlet weak var cityLabel: UILabel! @IBOutlet weak var hrsLabel: UILabel! var timer = Timer() var cityName:String! override func awakeFromNib() { super.awakeFromNib() self.accessoryView = timeLabel } func setCity(name:String){ cityLabel.text = name timeLabel.text = timeZone(city: name) hrsLabel.text = "Today,+0HRS" cityName = name timer = Timer.scheduledTimer( timeInterval: 1.0, // 時間間隔 target: self, // タイマーの実際の処理の場所 selector: #selector(WorldClockCell.tickTimer(_:)), // メソッド タイマーの実際の処理 userInfo: nil, repeats: true) RunLoop.main.add(timer, forMode: RunLoop.Mode.common) } @objc func tickTimer(_ timer: Timer) { timeLabel.text = timeZone(city: cityName) } func timeZone(city:String) -> String{ let formatter = DateFormatter() formatter.dateFormat = "HH:mm" formatter.timeStyle = .short formatter.locale = Locale(identifier: "ja_JP") let timeZoneIdentifiers = TimeZone.knownTimeZoneIdentifiers for identifier in timeZoneIdentifiers { if identifier.contains(city){ formatter.timeZone = TimeZone(identifier: identifier) } } let timeDiff = formatter.timeZone.secondsFromGMT() hrsLabel.text = timeDiff.timeString() return formatter.string(from: Date()) } } extension Int { func timeString() -> String { let adjustSecondsForJapan : TimeInterval = 9 * 60 * 60 let formatter = DateComponentsFormatter() formatter.allowedUnits = [.day,.hour, .minute] formatter.unitsStyle = .positional let formattedString = formatter.string(from: TimeInterval(self) - adjustSecondsForJapan) ?? "0" let df = DateFormatter() df.dateStyle = .short df.doesRelativeDateFormatting = true let day = df.string(from: Date(timeIntervalSinceNow: TimeInterval(self) - adjustSecondsForJapan)) if formattedString == "0" { return day + ", +0HRS" } else { if formattedString.hasPrefix("-") { return day + ", \(formattedString)HRS" } else { return day + "+\(formattedString)HRS" } } } }
WorldClockSelectVC
import UIKit protocol WorldClockSelectVCDelegte { func worldClockSelect(selectedWorldClock:WorldClockSelectVC,selected:String) func worldClockSelect(cancel:WorldClockSelectVC) } class WorldClockSelectVC: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var nav: UINavigationBar! var delegate:WorldClockSelectVCDelegte! private var searchController: UISearchController! var filteredTitles = [[String]]() var timeZoneIdentifiers = [String]() var allCities: [String] = [] var sortedFirstLetters: [String] = [] var sections: [[String]] = [[]] var searchString:String = "" override func viewDidLoad() { super.viewDidLoad() searchController = UISearchController(searchResultsController: nil) searchController.searchResultsUpdater = self searchController.obscuresBackgroundDuringPresentation = false searchController.dimsBackgroundDuringPresentation = false searchController.searchBar.sizeToFit() searchController.searchBar.showsCancelButton = true searchController.searchBar.delegate = self // UISearchControllerをUINavigationItemのsearchControllerプロパティにセットする。 navigationItem.searchController = searchController // trueだとスクロールした時にSearchBarを隠す(デフォルトはtrue) // falseだとスクロール位置に関係なく常にSearchBarが表示される navigationItem.hidesSearchBarWhenScrolling = false NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) timeZoneIdentifiers = TimeZone.knownTimeZoneIdentifiers.sorted() for identifier in timeZoneIdentifiers { if let cityName = identifier.split(separator: "/").last { allCities.append("\(cityName)") } } let firstLetters = allCities.map { $0[$0.startIndex].uppercased() } let uniqueFirstLetters = Array(Set(firstLetters)) sortedFirstLetters = uniqueFirstLetters.sorted() sections = sortedFirstLetters.map({firstLetter in return allCities.filter({ $0[$0.startIndex].uppercased() == firstLetter }).sorted(by: {$0 < $1}) }) filteredTitles = sections } @objc private func keyboardWillShow(notification: NSNotification) { if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue { tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0) } } @objc private func keyboardWillHide(notification: NSNotification) { tableView.contentInset = .zero } } // MARK: - UISearchResultsUpdating extension WorldClockSelectVC: UISearchResultsUpdating ,UISearchBarDelegate{ func updateSearchResults(for searchController: UISearchController) { // SearchBarに入力したテキストを使って表示データをフィルタリングする。 searchString = searchController.searchBar.text ?? "" if searchString.isEmpty { filteredTitles = sections } else { filteredTitles = sections.map({ filter in return filter.filter({$0.contains(searchString)}) } ) } tableView.reloadData() } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { delegate.worldClockSelect(cancel: self) dismiss(animated: true, completion: nil) } } // MARK: - UITableViewDataSource UITableViewDelegate extension WorldClockSelectVC: UITableViewDataSource,UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return filteredTitles[section].count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = filteredTitles[indexPath.section][indexPath.row] return cell } public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return searchString != "" ? nil : sortedFirstLetters[section] } func numberOfSections(in tableView: UITableView) -> Int { return filteredTitles.count } public func sectionIndexTitles(for tableView: UITableView) -> [String]? { return searchString != "" ? nil : sortedFirstLetters } public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { return UILocalizedIndexedCollation.current().section(forSectionIndexTitle: index) } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { searchController.searchBar.resignFirstResponder() searchController.dismiss(animated: false) delegate.worldClockSelect(selectedWorldClock: self, selected: filteredTitles[indexPath.section][indexPath.row]) dismiss(animated: true, completion: nil) } }githubはこちら
参考
UISearchControllerの使い方。主に結果画面からNavigationControllerでPushswift – カスタムモデルクラスを使用して、tableView内のデータをセクションごとにアルファベット順にソートする方法
Replacement of date object with “today” and “yesterday” strings in iphone
0 件のコメント:
コメントを投稿