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 件のコメント:
コメントを投稿