语境
ViewCode是一个仅使用方式来描述用户界面的构建的术语。最初,屏幕是通过Xcode本身的谷物接口使用故事板/XIB创建的。 Pordi,有一些问题:
- 限制对元素属性的访问
- 文件修改冲突(合并地狱)
- 当应用程序越来越大时,文件很重,并导致xcode(故事板)
入口,创建了一种新模式,绰号为ViewCode
。在本文中,我们将简要看到它是如何工作的以及如何根据此格式从零创建应用程序的。
概括
创建应用程序
显然,第一步是创建一个应用程序。要创建本教程,我正在使用Xcode 14.3.1。如果您使用的是不同的版本,则可能会更改一些细节。
首先,我们打开Xcode,然后单击Create a new Xcode Project
:
this,Xcode将为创建应用程序类型打开一个窗口:
对于本教程,我们将选择koud2平台和koud3选项,然后单击Next
:
下一步是命名项目并选择一些基本配置,例如应用程序名称,时间, bundle标识符,接口类型(UI)和语言。也可以选择使用与云同步的CoreData
并包括测试。对于本教程,最重要的是选择修改以下选项:
-
Interface → Storyboard
Language → Swift
因此,我们保证我们的应用程序将被配置为使用Swift语言(而不是OBJ-C),并且按标准化将使用故事板(而不是Swifti)创建接口。
apons单击Next
,xcode将提供一个屏幕,以选择要从项目中保存文件的位置。
bast选择所需的文件夹,然后单击Create
botan。这样,您的项目将由Xcode创建和打开:
现在我们已经有了一个新项目,让我们转到下一步:删除故事板。
删除情节提要
在ExampleApp
项目的属性中,它在创建之后很快就打开了,我们需要访问Koud11选项卡,如果您偶然地关闭此窗口,可以通过在左侧栏中的项目项目中单击两次:
在Koud11选项卡中,在Koud13部分中,找到项目Main Storyboard file base name
和Application Scene Manifest → Scene Configuration → Default Configuration > Storyboard name
并将它们从列表中删除,使用较少的ãconi与项目名称或选择它并按下删除/backspace键:
apons删除这些项目,我们可以从我们的项目中删除Main.storyboard
文件,因为这将不需要。为此,只需在左侧侧边栏中找到它,然后使用Cmd+Delete
快捷方式或快捷菜单删除它,如下所示:
现在我们的项目没有另一个故事板文件,我们可以开始使用ViewCode构建的应用程序。
ViewCode
配置ViewCode
我们没有更多的故事板来介绍我们的屏幕,我们需要定义一个新的负责此演示文稿。为此,我们将访问Koud18文件并在整个scene
中进行一些修改。最初,它已经带有一些评论,但是要缩短代码伸展,在此示例中已将其删除。最初,这是母亲的全部:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else {
return
}
// [...] Outros métodos do SceneDelegate
}
首先,我们将获得整个母亲收到的Koud19,并试图将其转换为UIWindowScene
。这已经在整体上写成,由于let _ = [...]
,对话的价值被丢弃了。为此,只需命名获得值的职责:
guard let windowScene = (scene as? UIWindowScene) else {
return
}
我们需要进行此转换并获得值
self.window = UIWindow(windowScene: windowScene)
有了一个确定的窗口,下一步是实例化要显示的UINavigationController
,以便在支持导航的情况下构建我们的应用程序。
ExampleApp
项目是用示例的ViewController
创建的,它将是我们应用程序导航的主屏幕(rootViewController
):
let navigationController = UINavigationController(rootViewController: ViewController())
现在我们已经有了UINavigationController
,我们可以将其定义为window
中屏幕的根(rootViewController
)。然后,我们将其定义为主,并通过母亲在屏幕上呈现©All makeKeyAndVisible
:
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
在上面提到的每个步骤之后,我们将有以下内容:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else {
return
}
self.window = UIWindow(windowScene: windowScene)
let navigationController = UINavigationController(rootViewController: ViewController())
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
// [...] Outros métodos do SceneDelegate
}
下一步包括创建通过协议构建视图的模式。
创建一个ViewCode协议
一个非常有趣的标准化是创建一个协议,该协议将定义在ViewCode中必须具有的UIView
的格式。这样,所有视图都具有相同的构建方式,并且会更幻想找到重要信息。
接下来,一个协议建议,具有维持构建良好的观点的必要基本建议:
// Arquivo ViewCode.swift
protocol ViewCode {
func addSubviews()
func setupConstraints()
func setupStyle()
}
extension ViewCode {
func setup() {
addSubviews()
setupConstraints()
setupStyle()
}
}
每个母亲的简短说明©上面定义的所有定义:
-
addSubviews()
:将视图添加为子视图,并定义它们之间的层次结构 -
setupConstraints()
:定义用于将元素定位在视图中的约束 -
setupStyle()
:定义视图样式,例如颜色,边缘等。 -
setup()
:作为视图初始化标准过程的一部分,执行以前的三个母亲
注意:我们在协议extension
中创建了整个setup
,因为不可能直接在协议中创建母亲的实现。但是,这样做,我们设法以一个被称为母亲setup()
的母亲总结了设置。在下一步中,我们将在实用中看到这一点。
准备好协议后,我们可以创建一种观点,并根据它更好地了解该结构的工作原理。
使用ViewCode创建视图
作为一个例子,我们将为拥有文本和botan的Koud27创建视图。为此,我们将需要UIKit
框架中包含的elements UILabel
和koud43。
首先,让我们使用我们的koud46类的koud45文件,它继承了UIView
的特征:
// Arquivo View.swift
// Importamos o UIKit
import UIKit
class View: UIView {
init() {
// Chamamos um método da UIView para inicialização
super.init(frame: .zero)
}
// O método a seguir é obrigatório na classe UIView
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
现在我们有了一个View
,我们可以创建将会显示在其中的视图。如前所述,文本和植物体:
// Arquivo View.swift
// Importamos o UIKit
import UIKit
class View: UIView {
private lazy var label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var button: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.blue, for: .normal)
return button
}()
init() {
// Chamamos um método da UIView para inicialização
super.init(frame: .zero)
}
// O método a seguir é obrigatório na classe UIView
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(labelText: String, buttonTitle: String) {
label.text = labelText
button.setTitle(buttonTitle, for: .normal)
}
}
也许以上的范围使您的脑海有很多不同,也许是未知的概念。下面,可能出现的问题的一些答案:
- 为什么使用
private
访问修饰符?
以防止视图被修改。遵循封装的原则,我们只暴露了严格必要的内容,从而阻止了我们的观点的性质进行不当修改。为了允许配置视图,我们可以创建一个具有必要信息的整个setup
。
- 为什么要使用koud51?
英语的术语懒惰将我们的观点描述为“懒惰”。从字面上看她是什么。使用此关键字,我们定义的是,将第一次访问koud52属性的值定义。在定义之后,可能不会更改此值。在什么情况下?当我们有条件渲染时。如果如果满足条件,则添加了视图,我们会阻止其在成员中占据不必要。
- 或那个©
label: UILabel= { /* ... */ }()
上面的摘录称为自我执行闭合。类似于其他语言中的矮人功能。在这种情况下,好像我们声明了一个函数,并立即被调用。在Swift中,这意味着创建闭合并立即摇动它。
- 这样可以使用
translatesAutoresizingMaskIntoConstraints
?
此属性定义为false
,以允许我们定义的约束,不要与系统自动生成的约束相冲突。因此,我们可以定义我们的约束并根据需要定位元素。
- 你为什么都
setup(labelText:,buttonTitle:)
?
允许我们配置View
的信息,而无需公开每个子视图。这样,我们将个性化仅限于标签的文本和button
的标题。
上面的概念遵循使用ViewCode查看视图的最推荐实践。既然你们都启发了,我们可以转到下一步:根据ViewCode
协议来表达我们的视图。
extension View: ViewCode {
func addSubviews() {
addSubview(label)
addSubview(button)
}
func setupConstraints() {
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: centerXAnchor),
label.centerYAnchor.constraint(equalTo: centerYAnchor),
button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
button.centerXAnchor.constraint(equalTo: centerXAnchor)
])
}
func setupStyle() {
backgroundColor = .white
}
}
在上面的摘录中,我们使用ViewCode
协议中定义的母亲进行:
- 添加
label
和koud58 - nossaView
- 将koud52放置在
View
中的水平集中(广播)和垂直(centeryanchor) - 位置koud58水平集中(centroxanchor),并垂直到我们koud52的底部(koud68)到
8
空间 - 将
View
的背景颜色定义为白色(.white
)
现在,我们只需要在Koud73上致电Koud46设置:
// Arquivo View.swift
// Importamos o UIKit
import UIKit
class View: UIView {
private lazy var label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var button: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.blue, for: .normal)
return button
}()
init() {
// Chamamos um método da UIView para inicialização
super.init(frame: .zero)
// Chamamos o setup da nossa view
setup()
}
// O método a seguir é obrigatório na classe UIView
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(labelText: String, buttonTitle: String) {
label.text = labelText
button.setTitle(buttonTitle, for: .normal)
}
}
extension View: ViewCode {
func addSubviews() {
addSubview(label)
addSubview(button)
}
func setupConstraints() {
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: centerXAnchor),
label.centerYAnchor.constraint(equalTo: centerYAnchor),
button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
button.centerXAnchor.constraint(equalTo: centerXAnchor)
])
}
func setupStyle() {
backgroundColor = .white
}
}
构建koud46后,我们可以在koud27中使用它。
在ViewController上使用视图
现在,我们返回以前创建的ViewController
,我们可以使用View
在屏幕上显示:
// Arquivo ViewController.swift
class ViewController: UIViewController {
private lazy var myView: View = {
return View()
}()
// Método do ciclo de vida que carrega a view
override func loadView() {
super.loadView()
self.view = myView
}
override func viewDidLoad() {
super.viewDidLoad()
// Configuramos a View usando o método setup
myView.setup(labelText: "Olá, mundo!", buttonTitle: "Testar")
}
}
这是最后一步,因此我们能够显示使用ViewCode
模式创建的View
。如果运行应用程序,请参见以下结果:
好吧,现在我们有一个使用ViewCode构建的屏幕。 por©m,缺少最后一个细节:我们创建了一个按钮,但没有任何交互。我们的下一步将是创建此互动。
为botan添加动作
首先,让我们为我们的观点创建一个Delegate
,这是Uikit本身中所采用的模式,当我们需要“转发”一个动作/信息之外,“委派”处理它的责任。我们将打电话给您Koud81:protocol ViewDelegate: AnyObject {
func didTapButton()
}
奇怪的是在这段时间里出现了什么,不是吗?为什么我们的协议符合AnyObject
协议?为了允许我们的代表成为weak
-type参考,它仅是对象,因此避免了保留周期。这是本文中不会出现的更复杂的细节(这已经是广泛的),但是了解动机很重要。
现在,我们需要在我们的koud46上创建一个delegate
属性,以处理按钮的动作:
protocol ViewDelegate: AnyObject {
func didTapButton()
}
class View: UIView {
// ...
private lazy var button: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, selector: #selector(didTapButton), for: .touchUpInside)
return button
}()
weak var delegate: ViewDelegate?
// ...
@objc
private func didTapButton() {
delegate?.didTapButton()
}
}
解释上面的拉伸:
-
delegate
:使用弱改进的属性(weak
)和可选(?
),以便View
可以通知谁在使用该动作,作为 -
@objc
:母亲的这一属性©AlldidTapButton
允许他与Objective-C进行互动,这就是Uikit的大部分情况。在这种情况下,有必要在#selector
中使用整个将其添加到 -
addTarget(_ target:, action:, for:
):母亲©全部用于将动作添加到植物体中。第一个仪表Koud94会在整体所在的位置接收到类改进,第二个仪表本身会收到动作本身,为此我们使用了Koud95。最后,在koud96,我们告知整个被要求触摸botan,所以koud97。
完成此操作后,我们在View
方面都有所有配置来处理操作。现在,我们需要指定查看controller处理操作的责任:
class ViewController: UIViewController {
private lazy var myView: View = {
let view = View()
// Atribuimos a ViewController como delegate
view.delegate = self
return view
}()
// ...
}
extension ViewController: ViewDelegate {
func didTapButton() {
// Nossa ação irá atualizar a View
myView.setup(labelText: "Sucesso!", buttonTitle: "Testar novamente")
}
}
在上面的拉伸中,我们修改了ViewController
以归因于koud46的delegate
,并符合Koud81协议以处理触摸按钮。玩植物体时,我们的ViewController
用新信息更新了koud46,离开:
包括£o
浏览本教程的每个阶段,您将足够意识
本文的全部方式可以在此重新定位中找到:
reisdev / viewcode-example-ios
使用本文创建的应用程序的存储库:
有丹吗?将其留在评论中,或在我的任何网络中寻找我,您可以找到aqui
在下一篇文章ð½。
capa por UX Store如果Abiaoqian 36