我刚开始从Interface Builder迁移到100%代码。
我已成功创建了自动布局单屏应用程序作为概念验证。问题是,我觉得好像有一种更有效的方法。
从UIView类中获取对象并在UIViewController
中访问对象的正确方法是什么?
这是我整个项目的代码
AppDelegate.swift 。
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
}
ViewControllerView.swift
import UIKit
public enum ViewControllerTextFields: String {
case username = "usernameField"
case password = "passwordField"
}
public enum ViewControllerButtons: String {
case login = "loginButton"
}
class ViewControllerView: UIView {
private var views = [String: UIView]()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .lightGray
createScreenComponents()
createConstraints()
}
func makeTextField(withPlaceholder text: String, textColor color: UIColor) -> UITextField {
let textField = UITextField()
textField.attributedPlaceholder = NSAttributedString(string: text, attributes: [.foregroundColor : color.withAlphaComponent(0.5)])
textField.textColor = color
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}
func makeButton(withTitle title: String) -> UIButton {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle(title, for: .normal)
return button
}
func createScreenComponents() {
let usernameField = makeTextField(withPlaceholder: "Username", textColor: .white)
let passwordField = makeTextField(withPlaceholder: "Password", textColor: .white)
let loginButton = makeButton(withTitle: "Login")
views["usernameField"] = usernameField
views["passwordField"] = passwordField
views["loginButton"] = loginButton
}
func createConstraints() {
for (key, val) in views {
addSubview(val)
addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "H:|[\(key)]|",
options: [],
metrics: nil,
views: views)
)
}
addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "V:|[usernameField]",
options: [],
metrics: nil,
views: views)
)
addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "V:[usernameField][passwordField(==usernameField)]",
options: [],
metrics: nil,
views: views)
)
addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "V:[passwordField][loginButton(==passwordField)]|",
options: [],
metrics: nil,
views: views)
)
}
public func getTextFieldWithId(_ identifier: ViewControllerTextFields) -> UITextField {
return views["\(identifier.rawValue)"] as! UITextField
}
public func getButtonWithID(_ identifier: ViewControllerButtons) -> UIButton {
return views["\(identifier.rawValue)"] as! UIButton
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
var username: UITextField!
var password: UITextField!
override func loadView() {
let viewObject = ViewControllerView()
view = viewObject
username = viewObject.getTextFieldWithId(.username)
password = viewObject.getTextFieldWithId(.password)
viewObject.getButtonWithID(.login).addTarget(self, action: #selector(test), for: .touchUpInside)
}
override func viewDidLoad() {
super.viewDidLoad()
}
@objc func test() {
print("Hello")
}
}
有没有办法访问ViewControllerView对象,如UITextFields和UIButtons,而不必使用viewObject
变量并使用函数返回视图?
答案 0 :(得分:1)
我的建议是在ViewController视图中保存文本字段和按钮的私有变量,但提供可在控制器中访问的只读变量,
在ViewControllerView.swift中:
private var _username: UITextField!
private var _password: UITextField!
private var _login: UIButton!
var username: UITextField! { get { return _username } }
var password: UITextField! { get { return _password } }
var login: UIButton! { get { return _login } }
然后在ViewController.swift中,您可以替换以下行:
username = viewObject.getTextFieldWithId(.username)
password = viewObject.getTextFieldWithId(.password)
viewObject.getButtonWithID(.login).addTarget(self, action: #selector(test), for: .touchUpInside)
使用:
username = viewObject.username
password = viewObject.password
viewObject.login.addTarget(self, action: #selector(test), for: .touchUpInside)
如果愿意,您甚至可以将这些变量作为实例变量存储在ViewController类中。
答案 1 :(得分:0)
我认为这是一种更合乎逻辑且更容易实现的方式:
// Typical AppDelegate.swift for running WITHOUT storyboard
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
}
// our start-up View Controller
import UIKit
class ViewController: UIViewController {
var theVCView = ViewControllerView()
override func viewDidLoad() {
super.viewDidLoad()
// replace "default" view with our custom view
self.view = theVCView
// example of adding a "Call Back" closure to "hear from" and get access to the custom view elements
theVCView.buttonCallBackAction = {
_ in
var sUsername = ""
var sPassword = ""
if let t = self.theVCView.usernameField.text {
sUsername = t
}
if let t = self.theVCView.passwordField.text {
sPassword = t
}
print("Username:", sUsername)
print("Password:", sPassword)
// do whatever else you want here...
}
}
}
// and... our custom UIView
import UIKit
class ViewControllerView: UIView {
lazy var usernameField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.attributedPlaceholder = NSAttributedString(string: "Username", attributes: [NSForegroundColorAttributeName : (UIColor.white).withAlphaComponent(0.5)])
textField.textColor = .white
return textField
}()
lazy var passwordField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.attributedPlaceholder = NSAttributedString(string: "Password", attributes: [NSForegroundColorAttributeName : (UIColor.white).withAlphaComponent(0.5)])
textField.textColor = .white
return textField
}()
lazy var loginButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Login", for: .normal)
button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
return button
}()
// optional "Call Back" closure
var buttonCallBackAction : (()->())?
func buttonTapped(_ sender: Any?) -> Void {
buttonCallBackAction?()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
func commonInit() {
self.backgroundColor = .lightGray
createConstraints()
}
func createConstraints() {
let views = [
"usernameField": usernameField,
"passwordField": passwordField,
"loginButton": loginButton
] as [String : UIView]
for (key, val) in views {
addSubview(val)
addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "H:|[\(key)]|",
options: [],
metrics: nil,
views: views)
)
}
addConstraints(NSLayoutConstraint.constraints(
withVisualFormat: "V:|-80-[usernameField][passwordField(==usernameField)][loginButton(==passwordField)]",
options: [],
metrics: nil,
views: views)
)
}
}
现在,您拥有自定义视图的属性,您可以在" normal"方式。