awakeFromNib

本文详细解释了awakeFromNib和viewDidLoad的区别,说明了在使用nib文件创建视图对象时,awakeFromNib只在nib文件加载时触发,而viewDidLoad则在视图加载到内存中时始终执行。
awakeFromNib
当.nib文件被加载的时候,会发送一个awakeFromNib的消息到.nib文件中的每个对象,每个对象都可以定义自己的awakeFromNib函数来响应这个消息,执行一些必要的操作。也就是说通过nib文件创建view对象是执行awakeFromNib

viewDidLoad
当view对象被加载到内存是就会执行viewDidLoad,所以不管通过nib文件还是代码的方式创建对象都会执行viewDidLoad

所以用以下代码运行程序时不执行awakeFromNib
Java代码 收藏代码
  1. TestController*test=[[TestControlleralloc]initWithNibName:@"Test"bundle:nil];
  2. [self.viewaddSubview:test.view];


复制代码
而viewDidLoad不管在什么情况下都会执行
这是之前ai给出的修改方案: 当前的设备列表是“单列垂直滚动”,每个 `section` 的 header(即 `OnlineDeviceCardNormalHeader`)占据一整行,纵向排列。现在你想改成: > ✅ **每行显示两个设备卡片(双列网格布局)** 这本质上是从 **线性列表 → 网格布局(Grid Layout)** 的转变。 --- ## 🎯 目标效果 ``` +------------------+ +------------------+ | Device Card 1 | | Device Card 2 | | (with channels) | | (with channels) | +------------------+ +------------------+ +------------------+ +------------------+ | Device Card 3 | | Device Card 4 | | (with channels) | | (with channels) | +------------------+ +------------------+ ↓ 垂直滚动 ``` 也就是说: - 每个设备作为一个独立 item - 不再使用 `section header` 来展示设备 - 改用 `UICollectionViewCell` 实现设备卡片 - 内部仍保留通道横向滑动视图 --- ## 🔧 实现思路总览 | 步骤 | 内容 | | ---- | ------------------------------------------------------------ | | 1️⃣ | 修改数据结构:不再以 `section` 为单位,改为 flat list of devices | | 2️⃣ | 替换 UI 架构:从 “Section Header + Items” 改为 “Cell + Embedded CollectionView” | | 3️⃣ | 使用 `UICollectionViewCompositionalLayout` 实现双列网格 | | 4️⃣ | 复用现有组件:`OnlineDeviceCardNormalHeader` 可改造成普通 Cell | | 5️⃣ | 调整 Presenter:让 `ItemPresenter` 成为设备卡片本身 | --- # ✅ 分步详解 --- ## 第一步:重构数据源结构(去 Section 化) ### ❌ 当前模式(基于 Section) ```swift [SectionData<Header=LTopLevelDevice, Item=TPSSChannelInfo>] ``` → 每个 section 表示一个设备,header 是设备信息,items 是其通道 ### ✅ 新模式(扁平化) ```swift [DeviceItem] // [LTopLevelDevice] ``` → 每个 cell 显示一个设备及其所有通道预览 你需要在 `GeneralDeviceListViewController` 中提供一个新的数据源数组: ```swift var deviceList: [LTopLevelDevice] { return delegate?.allDevices() ?? [] } ``` 然后把这个列表交给新的 `UICollectionViewDataSource`。 --- ## 第二步:创建新 Cell —— 把 `OnlineDeviceCardNormalHeader` 改造成普通 Cell 你现在使用的 `OnlineDeviceCardNormalHeader` 是继承自 `UICollectionReusableView`,用于作为 header。 但我们要把它变成普通的 `UICollectionViewCell`。 ### ✅ 方案一:直接修改父类(推荐) 将 `OnlineDeviceCardNormalHeader` 改为继承自 `UICollectionViewCell`: ```swift class OnlineDeviceCardNormalHeader: UICollectionViewCell { @IBOutlet weak var deviceNameLabel: UILabel! @IBOutlet weak var coverImageView: UIImageView! @IBOutlet weak var channelListVerticalCollectionView: UICollectionView! private var channels: [TPSSChannelInfo] = [] override func awakeFromNib() { super.awakeFromNib() setupCollectionView() } private func setupCollectionView() { channelListVerticalCollectionView.delegate = self channelListVerticalCollectionView.dataSource = self channelListVerticalCollectionView.register( OnlineChannelCardCell.self, forCellWithReuseIdentifier: "OnlineChannelCardCell" ) } func apply(_ device: LTopLevelDevice, at indexPath: IndexPath) { deviceNameLabel.text = device.deviceName coverImageView.image = device.coverImage ?? UIImage(named: "default_cover") channels = device.channels ?? [] // 假设 model 提供了 channels channelListVerticalCollectionView.reloadData() } } ``` ✅ 这样它就可以被当作普通 cell 使用了! --- ## 第三步:注册并使用新 Cell 在 `viewDidLoad()` 中注册这个 cell: ```swift collectionView.register( OnlineDeviceCardNormalHeader.self, forCellWithReuseIdentifier: "OnlineDeviceCardNormalHeader" ) ``` --- ## 第四步:使用 `UICollectionViewCompositionalLayout` 实现双列网格 这是最核心的部分。 ### ✅ 创建两列等宽布局 ```swift func createTwoColumnLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(150) // 高度自适应 ) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(0.49), // 接近一半宽度,留点间距 heightDimension: .estimated(300) // 根据内容自动撑高 ) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) // 设置组间间距 group.interItemSpacing = .fixed(8) let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = 8 section.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8) section.orthogonalScrollingBehavior = .none // 禁止横向滚动 return UICollectionViewCompositionalLayout(section: section) } ``` ### 应用于 collectionView ```swift override func viewDidLoad() { super.viewDidLoad() collectionView.collectionViewLayout = createTwoColumnLayout() // 数据源切换为新的 flat list 模式 collectionView.dataSource = self // 或者新的 presenter } ``` --- ## 第五步:实现新的数据源方法(cellForItemAt) 你可以选择两种方式: ### ✅ 方式一:让 `GeneralDeviceListViewController` 自己做 DataSource ```swift extension GeneralDeviceListViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return deviceList.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell( withReuseIdentifier: "OnlineDeviceCardNormalHeader", for: indexPath ) as! OnlineDeviceCardNormalHeader let device = deviceList[indexPath.row] cell.apply(device, at: indexPath) return cell } } ``` ### ✅ 方式二:写一个新的 `GridModePresenter` 如果你希望保持架构一致,可以新建: ```swift private let gridModeDS = GridListViewPresenter< GeneralDeviceListViewController, OnlineDeviceCardNormalHeader >() ``` 其中 `GridListViewPresenter` 类似于原来的 `GeneralListViewPresenter`,但只处理 flat 列表。 --- ## 第六步:调整样式和交互 ### ✅ 添加点击事件(选中设备) 在 `OnlineDeviceCardNormalHeader` 中添加 tap gesture: ```swift override func awakeFromNib() { super.awakeFromNib() let tap = UITapGestureRecognizer(target: self, action: #selector(didTap)) self.addGestureRecognizer(tap) } @objc private func didTap() { delegate?.didSelectDevice(at: indexPath) // 可定义协议传递事件 } ``` ### ✅ 控制内层 CollectionView 高度(可选) 由于 `channelListVerticalCollectionView` 是嵌套的,建议设置固定高度或最大高度,避免影响外层 layout estimate。 ```swift // 在 storyboard 中给 channelListVerticalCollectionView 设定高度约束 // 或代码中添加: NSLayoutConstraint.activate([ channelListVerticalCollectionView.heightAnchor.constraint(equalToConstant: 120) ]) ``` --- ## ⚠️ 注意事项与避坑指南 | 问题 | 解决方案 | | ------------------------------------------- | ------------------------------------------------------------ | | ❌ `UICollectionReusableView` 不能当 Cell 用 | 改成继承 `UICollectionViewCell` | | ❌ 布局高度计算不准导致闪烁 | 给内层 collection view 设定固定高度 | | ❌ 卡片宽度不均 | 使用 `.fractionalWidth(0.49)` + `interGroupSpacing` 对齐 | | ❌ 滚动卡顿 | 启用 prefetching:<br>`collectionView.isPrefetchingEnabled = true` | | ❌ 图片异步加载延迟 | 使用 Kingfisher / SDWebImage 异步加载封面图 | --- ## ✅ 最终成果 你现在实现了: - ✅ 每行两个设备卡片 - ✅ 每个卡片包含设备基本信息 + 通道预览横滑列表 - ✅ 支持点击、复用、自动高度 - ✅ 架构清晰,易于扩展为三列或瀑布流 --- ## 💡 进阶建议 1. **支持动态列数**:根据屏幕尺寸自动切换单列/双列 2. **加入动画过渡**:切换布局时淡入淡出 3. **添加占位图**:无数据时显示 loading 或空状态 4. **性能优化**:对离屏 cell 中的 channel collectionView 暂停刷新 现在请根据这个意见,我现在要做ppt 需求分析-设备列表多列布局-解决方案,请帮我列出方案对比,原方案+具体实现方式以及现方案+具体实现方式。
最新发布
10-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值