iOS应用开发:自定义食谱视图

在iOS应用开发中,自定义视图是一个常见的需求。本文将介绍如何在Xcode中使用Xib和Nib文件来创建和管理自定义的食谱视图。

Xib和Nib文件的区别

首先,需要了解Xib和Nib文件的区别。Xib文件是Interface Builder的文件格式,用于定义用户界面。而Nib文件是Xib文件编译后生成的,用于在运行时恢复视图。

1. 打开Xcode,创建一个新的项目,命名为MyRecipes。

2. 进入项目导航器,将ViewController重命名为RecipesViewController。

3. 打开main.storyboard,选择ViewController,然后在Identity Inspector中选择RecipesViewController。

4. 在RecipesViewController中添加UITableView,并确保只有一个Prototype Cell,命名为'cell'。

1. 向项目中添加一个新的Cocoa Touch Class,命名为RecipeItemView。

2. 创建一个名为RecipeItemView的Xib文件,并根据需要更新它。

3. 在Xib文件中,会看到两个同名的文件,一个是Swift扩展,另一个是Xib扩展。Nib文件是在Xib文件编译时由Xcode创建的。

4. 要找到Nib文件,可以在Finder中打开以下路径:~/Library/Developer/Xcode/DerivedData/MyRecipes-.../Build/Products/Debug-iphonesimulator/MyRecipes。

5. 右键点击并选择“Show Package Contents”,将看到Nib文件。

如何使用Xib文件

Xib文件与用户界面相关联。在案例中,RecipeItemView.xib与RecipeItemView UIView类相关联。将使用这个视图作为UITableViewCell的内容视图。因此,需要下载Nib文件,将其解析为RecipeItemView类,并将其作为子视图添加到cell的内容视图。

有两种方法可以从Nib文件中获取视图类。

1. 下载Nib文件内容作为数组。Xib文件可以包含一个或多个UIView或UIViewController元素。要获取它们,调用loadNibNamed:

let elementsOfNib = Bundle.main.loadNibNamed("RecipeItemView", owner: nil, options: nil)

函数返回一个可选值。要获取数组中的视图,可以使用索引或类似的方法:

let recipesItemView = elementsOfNib?.first

recipesItemView是一个可选的RecipeItemView类实例,具有初始化的outlets。

2. 使用带有owner参数的loadNibNamed调用:

Bundle.main.loadNibNamed("RecipeItemView", owner: self, options: nil)

这里的self参数是什么?为什么不将结果赋值给任何东西?让一步一步考虑。

打开RecipeItemView.xib文件,并将Placeholders—File’s Owner设置为RecipesViewController。

打开RecipesViewController.swift,添加@IBOutlet var:

class RecipesViewController: UIViewController { … @IBOutlet var itemView: RecipeItemView! }

返回Xib编辑屏幕。选择File’s Owner,按住鼠标右键,拖动到RecipeItemView。

从上下文菜单中选择itemView。从现在开始,将File owner和Xib的元素绑定在一起。

返回loadNibNamed:

Bundle.main.loadNibNamed("RecipeItemView", owner: self, options: nil)

这里的self是RecipesViewController。当这个函数返回时,变量itemView将自动获得值。它是RecipeItemView实例。

如何使TableViewCell自动调整大小

将RecipeItemView的titleLabel、imageView和descriptionLabel的高度约束与NSLayoutConstraint的outlets绑定。

打开RecipesViewController,从viewDidLoad方法配置UITableView:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { cell.layoutIfNeeded() }

打开RecipeItemView.swift,计算高度约束:

func configure(with cell: UITableViewCell, model: RecipeData?, width: CGFloat) { guard let model else { return } titleLabel.text = model.title imageView.image = model.image descriptionLabel.text = model.description let h1 = model.title?.height(for: width, font: titleLabel.font) ?? 0 let h2 = model.image?.height(for: width) ?? 0 let h3 = model.description?.height(for: width, font: descriptionLabel.font) ?? 0 titleLabelHeight.constant = h1 imageViewHeight.constant = h2 descriptionLabelHeight.constant = h3 let height: CGFloat = h1 + h2 + h3 + 5.0 * 4 translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ leadingAnchor.constraint(equalTo: cell.leadingAnchor), trailingAnchor.constraint(equalTo: cell.trailingAnchor), topAnchor.constraint(equalTo: cell.topAnchor), bottomAnchor.constraint(equalTo: cell.bottomAnchor), heightAnchor.constraint(equalToConstant: height) ]) }

下一步也是最后一步是准备UITableViewCell。覆盖UITableViewDataSource代理的两个方法:

func tableView(_ tableView:UITableView, numberOfRowsInSection section: Int) -> Int { viewModel.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) Bundle.main.loadNibNamed("RecipeItemView", owner: self, options: nil) // itemView现在已加载。可以使用它。 cell.addSubview(itemView!) itemView!.configure(with: cell, model: viewModel[indexPath.row], width: tableView.frame.width) return cell }

TableViewCell应该根据内容调整其高度。

struct RecipesContentView: View { @EnvironmentObject var viewModel: RecipesFakeData var body: some View { GeometryReader { geometry in VStack { NavigationBar() List { ForEach(0.. CGFloat { if let model = viewModel[index], let view = Bundle.main.loadNibNamed("RecipeItemView", owner: nil, options: nil)?.first as? RecipeItemView { var height = model.title?.height(for: width, font: view.titleLabel.font) ?? 0 height += model.image?.height(for: width) ?? 0 height += model.description?.height(for: width, font: view.descriptionLabel.font) ?? 0 return height + 5.0 * 3 // 参考RecipeItemView.xib布局 } return 0.0 } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485