我正在设置一个非常简单的 iPhone 应用程序,它有多个文本字段,使用日期选择器控件输入日期和时间字符串。
问题是,虽然一切都运行良好,但我发现我正在为多个字段重复大量代码,这感觉很糟糕。
我想要的是一种将这段代码压缩到一个单独的类中,并在需要时从任何地方简单地调用它的方法。
下面是我的 View Controller 中的一个示例,它运行良好,但必须为多个字段重复多次:
@IBOutlet weak var dateField: UITextField!
@objc func dateFieldModified(sender:UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
dateField.text = dateFormatter.string(from: sender.date)
}
@IBAction func dateFieldModify(_ sender: UITextField) {
let datePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePicker.Mode.date
datePicker.addTarget(self, action: #selector(self.dateFieldModified(sender:)), for: UIControl.Event.valueChanged)
dateField.inputView = datePicker
}
总而言之,当用户输入文本字段“dateField”时,会弹出一个日期选择器并允许用户滚动并选择一个日期。当用户选择日期时,文本字段会设置为反射(reflect)所选日期。
我想在我的 View Controller 中做的是做这样的事情:
@IBOutlet weak var dateField: UITextField!
@IBAction func dateFieldModify(_ sender: UITextField) {
let datePicker = DatePicker(field:dateField, mode:"date", format: "MM/dd/yyyy")
datePicker.loadDatePicker()
}
并且有一个单独定义的类可能看起来像这样:
class DatePicker {
var field:UITextField
var mode:String
var format:String
init(field:UITextField, mode:String, format:String) {
self.field = field
self.mode = mode
self.format = format
}
@objc func dateFieldModified(sender:UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
field.text = dateFormatter.string(from: sender.date)
}
func loadDatePicker() {
let datePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePicker.Mode.date
datePicker.addTarget(self, action: #selector(self.dateFieldModified(sender:)), for: UIControl.Event.valueChanged)
field.inputView = datePicker
}
}
实现我上面写的新 DatePicker 类,几乎一切正常:当我单击“dateField”文本字段时,日期选择器打开,我可以滚动并选择一个日期。然而,在选择一个日期之后... dateField 仍然是空的。
我通常是 Swift 和 OOP 的新手,所以我确定我遗漏了一些代码或一个重要的概念。
最佳答案
是的,您可以(并且可能应该)将此逻辑封装在一个单独的类中。但正如 OOPer 所说,您可能想为此定义一个 UITextField 子类。
我会提出一些其他建议:
我建议您为该文本字段提供一个 date 属性,以便您可以设置和检索与该文本字段关联的 Date。就像 UIDatePicker 一样, View Controller 应该通过 date 属性与这个新控件交互,而不必自己处理日期格式化程序。
当使用日期选择器作为输入源时,我认为添加一个带有“完成”按钮的工具栏是很好的,这样用户就可以关闭输入源(就像您可以使用弹出的键盘一样上。
我不建议将 dateFormat 与 DateFormatter 一起使用,而是建议使用 dateStyle 和 timeStyle .您总是希望您的用户界面显示本地化的日期字符串。
您可能应该处理可能连接到设备的硬件键盘(如果针对 iPad,则尤其重要)。因此,您可能希望日期文本字段直接了解文本字段中字符串的修改以及从日期选择器中选择日期。
您可能需要自己的文本字段协议(protocol)来告知 UI 日期值的更改。
因此,我可能会建议如下:
/// Date text field delegate protocol
@objc protocol DateTextFieldDelegate {
@objc optional
func dateTextField(_ dateTextField: DateTextField, didChangeDate: Date?)
@objc optional
func didTapDone(dateTextField: DateTextField)
}
/// Date text field
///
/// Used for entry of dates in UITextField, replacing keyboard with date picker.
class DateTextField: UITextField {
/// `DateTextField` delegate
///
/// You don't need to supply a delegate, but if you do, this will tell you as
/// the user changes the date.
weak var dateTextFieldDelegate: DateTextFieldDelegate?
/// Default date
///
/// If `nil`, uses today's date
var defaultDate: Date?
/// Date formatter for date
///
/// Feel free to change `dateStyle` and `timeStyle` to suit the needs of your app.
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
return formatter
}()
/// Date
///
/// The user's selected date.
var date: Date? {
didSet {
dateTextFieldDelegate?.dateTextField?(self, didChangeDate: date)
if !isManuallyEditing {
text = date.map { formatter.string(from: $0) }
}
datePicker.date = date ?? defaultDate ?? Date()
}
}
var dateTextFieldButtonType: DateTextFieldButtonType = .done {
didSet { doneButton?.title = dateTextFieldButtonType.buttonText }
}
/// The date picker.
lazy var datePicker: UIDatePicker = {
let picker = UIDatePicker()
picker.datePickerMode = .date
return picker
}()
// MARK: - Private properties
/// Private reference for "Done" button
private var doneButton: UIBarButtonItem!
/// Private flag is the user is manually changing the date.
private var isManuallyEditing = false
// MARK: - Initialization
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
}
// MARK: - Private utility methods
private extension DateTextField {
func configure() {
inputView = datePicker
datePicker.addTarget(self, action: #selector(datePickerModified(_:)), for: .valueChanged)
let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
doneButton = UIBarButtonItem(title: dateTextFieldButtonType.buttonText, style: .done, target: self, action: #selector(didTapDone(_:)))
clearButtonMode = .whileEditing
toolBar.setItems([space, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
toolBar.sizeToFit()
inputAccessoryView = toolBar
addTarget(self, action: #selector(textFieldModified(_:)), for: .editingChanged)
}
}
// MARK: - Actions
extension DateTextField {
@objc func didTapDone(_ sender: Any) {
if dateTextFieldButtonType == .select {
date = datePicker.date
}
resignFirstResponder()
dateTextFieldDelegate?.didTapDone?(dateTextField: self)
}
@objc func textFieldModified(_ textField: UITextField) {
isManuallyEditing = true
date = text.flatMap { formatter.date(from: $0) }
isManuallyEditing = false
}
@objc func datePickerModified(_ datePicker: UIDatePicker) {
date = datePicker.date
}
}
// MARK: - Enumerations
extension DateTextField {
enum DateTextFieldButtonType {
case select
case done
case next
}
}
extension DateTextField.DateTextFieldButtonType {
var buttonText: String {
switch self {
case .select: return NSLocalizedString("Select", comment: "DateTextFieldButtonType")
case .done: return NSLocalizedString("Done", comment: "DateTextFieldButtonType")
case .next: return NSLocalizedString("Next", comment: "DateTextFieldButtonType")
}
}
}
然后您可以在 IB 中指定 DateTextField 的基类而不是 UITextField,您就完成了。
或者,如果你想实现委托(delegate)协议(protocol),你可以这样做:
class ViewController: UIViewController {
@IBOutlet weak var textField: DateTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.dateTextFieldDelegate = self
}
}
extension ViewController: DateTextFieldDelegate {
func didTapDone(dateTextField: DateTextField) {
print("keyboard dismissed")
}
func dateTextField(_ dateTextField: DateTextField, didChangeDate date: Date?) {
print(date ?? "No date specified")
}
}
或者如果你想要日期和时间:
class ViewController: UIViewController {
@IBOutlet weak var textField: DateTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.datePicker.datePickerMode = .dateAndTime
textField.formatter.dateStyle = .full
textField.formatter.timeStyle = .medium
}
}
显然,您可以根据需要修改此行为,但它说明了这个想法。
但是你是正确的,你应该从你的 View Controller 中抽象出这个带有日期选择器的文本字段,并将它放在它自己的类中。并根据您认为最适合您的应用的任何行为来定制此子类。
关于ios - 有没有一种方法可以将我所有的 View Controller 日期选择器逻辑放入一个单独的类中以保持我的代码井井有条?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55554551/
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/
我有一个奇怪的问题:我在rvm上安装了rubyonrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested
我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog
我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查
我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c