resignfirstresponder

本文深入探讨了iOS开发中'first responder'的概念及其工作机制,解释了如何通过`resignFirstResponder`和`canResignFirstResponder`方法来管理应用程序的焦点。详细介绍了这些方法在不同场景下的应用,如文本编辑、输入框处理等,帮助开发者更好地控制用户界面的交互流程。

resignFirstResponder(交出自己的第一响应者的身份,可以重写改函数,这样如果写出no的时候当调用这个方法的时候它会拒绝交出第一响应者的身份)

Notifies the receiver that it has been asked to relinquish(交出)its status as first responder in its window.

- (BOOL)resignFirstResponder

Discussion

The default implementation returns YES, resigning first responder status. Subclasses can overridethis method to update state or perform some action such as unhighlighting theselection, or to return NO, refusing torelinquish first responder status.

 

canResignFirstResponder

Returns a Boolean value indicating whether the receiver iswilling to relinquish first-responder status.

- (BOOL)canResignFirstResponder

Return Value

YES if the receiver canresign(辞职 消去) first-responder status, NO otherwise.

Discussion

Returns YES by default. Asan example, a text field in the middle of editing might want to implement thismethod to return NO to keep itself activeduring editing.

 

isFirstResponder

Returns a Boolean value indicating whether the receiver is thefirst responder.

- (BOOL)isFirstResponder

Return Value

YES if the receiver is thefirst responder, NO otherwise.


import UIKit import SnapKit class DeviceListNewViewController: SurveillanceCommonTableController { // MARK: - 属性 private lazy var titleView: UILabel = { let label = UILabel() label.text = "设备列表" label.font = .tpm20Medium() label.textColor = .tpbTextPrimary label.textAlignment = .center return label }() private lazy var searchBar: TPBSearchBar = { let bar = TPBSearchBar() bar.placeholder = "搜索" bar.backgroundColor = .clear bar.delegate = self return bar }() private lazy var searchContainerView: UIView = { let view = UIView() view.backgroundColor = UIColor(white: 0.96, alpha: 1.0) view.layer.cornerRadius = 22 view.clipsToBounds = true view.addSubview(searchBar) return view }() private lazy var tabScrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.showsHorizontalScrollIndicator = false scrollView.backgroundColor = .clear scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() private lazy var tabButtons: [UIButton] = { return tabButtonTitles.enumerated().map { index, title in let btn = UIButton(type: .custom) btn.tag = index btn.setTitle(title, for: .normal) btn.titleLabel?.font = UIFont.tpr14Regular() btn.setTitleColor(.black, for: .normal) btn.setTitleColor(.tpbPrimary, for: .selected) btn.layer.borderWidth = 1 btn.layer.borderColor = UIColor(white: 0.85, alpha: 1.0).cgColor btn.layer.cornerRadius = 20 btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) btn.addTarget(self, action: #selector(onTabTapped(_:)), for: .touchUpInside) return btn } }() private let tabButtonTitles = ["所有设备", "收藏页面", "站点选择"] private var selectedTabIndex = 0 // MARK: - View Setup override func tpbSetupSubviews() { super.tpbSetupSubviews() setupNav() view.addSubview(titleView) view.addSubview(searchContainerView) view.addSubview(tabScrollView) // 初始化按钮选中状态 updateTabSelection(index: selectedTabIndex) // 👇 直接在这里布局 tab 按钮(内联实现,避免找不到方法) layoutTabButtonsInScrollView() } private func setupNav() { navigationItem.leftBarButtonItem = tpbCreateLeftBarButtonItem( with: TPImageLiteral("icon_back"), andTarget: self, andAction: #selector(onBack) ) navigationItem.rightBarButtonItem = tpbCreateRightBarButtonItem( with: TPImageLiteral("icon_settings"), andTarget: self, andAction: #selector(onSettings) ) navigationItem.title = "" } override func tpbMakeConstraint() { super.tpbMakeConstraint() titleView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(8) make.centerX.equalToSuperview() } searchContainerView.snp.makeConstraints { make in make.top.equalTo(titleView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(16) make.height.equalTo(44) // 固定高度适配 TPBSearchBar 常见大小 } searchBar.snp.makeConstraints { make in make.edges.equalTo(searchContainerView).inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) } tabScrollView.snp.makeConstraints { make in make.top.equalTo(searchContainerView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(0) make.height.equalTo(40) } } // MARK: - 内联布局 Tab 按钮(防止 “Cannot find” 错误) private func layoutTabButtonsInScrollView() { // 清空之前的内容 tabScrollView.subviews.forEach { $0.removeFromSuperview() } var previousButton: UIButton? var currentX: CGFloat = 16 for button in tabButtons { tabScrollView.addSubview(button) // 使用固定 frame 或 SnapKit 设置位置 button.snp.makeConstraints { make in make.centerY.equalToSuperview() make.height.equalTo(36) if let prev = previousButton { make.leading.equalTo(prev.snp.trailing).offset(8) } else { make.leading.equalTo(tabScrollView.contentLayoutGuide).offset(16) } make.width.greaterThanOrEqualTo(80) } previousButton = button currentX += button.intrinsicContentSize.width + 8 } // 手动设置 contentSize(更稳定) DispatchQueue.main.async { var totalWidth: CGFloat = 16 for (i, btn) in self.tabButtons.enumerated() { totalWidth += btn.intrinsicContentSize.width + (i > 0 ? 8 : 0) } totalWidth += 16 self.tabScrollView.contentSize = CGSize(width: totalWidth, height: 40) } } // MARK: - 数据模型构建(仅搭建结构,不填充真实数据) private func reloadData() { var tempSectionArray = [TPBTableSectionModel]() let section0 = TPBTableSectionModel() var cellModels = [TPBBaseTableCellModel]() // Cell 1: Tab ScrollView let tabCellModel = TPBBaseTableCellModel.customContent(with: tabScrollView) cellModels.append(tabCellModel) // Cell 2: 占位用的 CollectionView 区域(仅视觉框架) let collectionViewPlaceholder = UIView() collectionViewPlaceholder.backgroundColor = .tpbBackground collectionViewPlaceholder.layer.cornerRadius = 12 collectionViewPlaceholder.clipsToBounds = true // 添加一个简单的提示标签表示“这里是列表” let placeholderLabel = UILabel() placeholderLabel.text = "设备内容区域" placeholderLabel.textColor = .tpbTextSecondaryContent placeholderLabel.font = .tpr14Regular() placeholderLabel.textAlignment = .center placeholderLabel.sizeToFit() collectionViewPlaceholder.addSubview(placeholderLabel) placeholderLabel.snp.makeConstraints { make in make.center.equalToSuperview() } let collectionCellModel = TPBBaseTableCellModel.customContent(with: collectionViewPlaceholder) collectionCellModel.height = TPBTableElementHeight.customHeight(240) cellModels.append(collectionCellModel) section0.cellModelArray = cellModels tempSectionArray.append(section0) sectionArray = tempSectionArray tableView.reloadData() } // MARK: - 生命周期 override func viewDidLoad() { super.viewDidLoad() reloadData() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 后续绑定 collectionView delegate } // MARK: - 点击事件 @objc private func onBack() { navigationController?.popViewController(animated: true) } @objc private func onSettings() { print("Settings tapped") } @objc private func onTabTapped(_ sender: UIButton) { guard sender.tag != selectedTabIndex else { return } tabButtons[selectedTabIndex].isSelected = false selectedTabIndex = sender.tag sender.isSelected = true // 后续刷新数据 print("Switched to tab: \(selectedTabIndex)") } private func updateTabSelection(index: Int) { for (i, btn) in tabButtons.enumerated() { btn.isSelected = (i == index) } } } // MARK: - TPBSearchBarDelegate(空实现,仅满足协议要求) extension DeviceListNewViewController: TPBSearchBarDelegate { func searchBar(_ searchBar: TPBSearchBar, textDidChange searchText: String) { // TODO: 搜索关键词变化时处理(后续接入 ViewModel) } func searchBarTextDidBeginEditing(_ searchBar: TPBSearchBar) { addTapToDismissKeyboard() } func searchBarTextDidEndEditing(_ searchBar: TPBSearchBar) { removeTapToDismissKeyboard() } func searchBarSearchButtonClicked(_ searchBar: TPBSearchBar) { searchBar.resignFirstResponder() } } // MARK: - Keyboard Dismiss Gesture private extension DeviceListNewViewController { func addTapToDismissKeyboard() { let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) objc_setAssociatedObject( self, &AssociatedKeys.searchBarTapGestureKey, tap, .OBJC_ASSOCIATION_RETAIN_NONATOMIC ) } func removeTapToDismissKeyboard() { guard let tap = objc_getAssociatedObject(self, &AssociatedKeys.searchBarTapGestureKey) as? UITapGestureRecognizer else { return } view.removeGestureRecognizer(tap) objc_setAssociatedObject(self, &AssociatedKeys.searchBarTapGestureKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } @objc func dismissKeyboard() { searchBar.resignFirstResponder() } } // MARK: - Associated Object Keys private struct AssociatedKeys { static var searchBarTapGestureKey: UInt8 = 0 } 现在这个,给我实现成这样的效果: 屏幕靠上部分显示titleview,然后下面显示searchbar,然后下面显示收藏按钮、所有设备那个scrollview,然后在下面显示一个UIcollectionView,滚动范围就在这个UICollectionView区域,明白我想要的结构了吗?修改代码 import UIKit import SnapKit class DeviceListNewViewController: SurveillanceCommonTableController { // MARK: - 属性 private lazy var titleView: UILabel = { let label = UILabel() label.text = "设备列表" label.font = .tpm20Medium() label.textColor = .tpbTextPrimary label.textAlignment = .center return label }() private lazy var searchBar: TPBSearchBar = { let bar = TPBSearchBar() bar.placeholder = "搜索" bar.backgroundColor = .clear bar.delegate = self return bar }() private lazy var searchContainerView: UIView = { let view = UIView() view.backgroundColor = UIColor(white: 0.96, alpha: 1.0) view.layer.cornerRadius = 22 view.clipsToBounds = true view.addSubview(searchBar) return view }() private lazy var tabScrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.showsHorizontalScrollIndicator = false scrollView.backgroundColor = .clear scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() private lazy var tabButtons: [UIButton] = { return tabButtonTitles.enumerated().map { index, title in let btn = UIButton(type: .custom) btn.tag = index btn.setTitle(title, for: .normal) btn.titleLabel?.font = UIFont.tpr14Regular() btn.setTitleColor(.black, for: .normal) btn.setTitleColor(.tpbPrimary, for: .selected) btn.layer.borderWidth = 1 btn.layer.borderColor = UIColor(white: 0.85, alpha: 1.0).cgColor btn.layer.cornerRadius = 20 btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) btn.addTarget(self, action: #selector(onTabTapped(_:)), for: .touchUpInside) return btn } }() private let tabButtonTitles = ["所有设备", "收藏页面", "站点选择"] private var selectedTabIndex = 0 // MARK: - View Setup override func tpbSetupSubviews() { super.tpbSetupSubviews() setupNav() view.addSubview(titleView) view.addSubview(searchContainerView) view.addSubview(tabScrollView) // 初始化按钮选中状态 updateTabSelection(index: selectedTabIndex) // 👇 直接在这里布局 tab 按钮(内联实现,避免找不到方法) layoutTabButtonsInScrollView() } private func setupNav() { navigationItem.leftBarButtonItem = tpbCreateLeftBarButtonItem( with: TPImageLiteral("icon_back"), andTarget: self, andAction: #selector(onBack) ) navigationItem.rightBarButtonItem = tpbCreateRightBarButtonItem( with: TPImageLiteral("icon_settings"), andTarget: self, andAction: #selector(onSettings) ) navigationItem.title = "" } override func tpbMakeConstraint() { super.tpbMakeConstraint() titleView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(8) make.centerX.equalToSuperview() } searchContainerView.snp.makeConstraints { make in make.top.equalTo(titleView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(16) make.height.equalTo(44) // 固定高度适配 TPBSearchBar 常见大小 } searchBar.snp.makeConstraints { make in make.edges.equalTo(searchContainerView).inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) } tabScrollView.snp.makeConstraints { make in make.top.equalTo(searchContainerView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(0) make.height.equalTo(40) } } // MARK: - 内联布局 Tab 按钮(防止 “Cannot find” 错误) private func layoutTabButtonsInScrollView() { // 清空之前的内容 tabScrollView.subviews.forEach { $0.removeFromSuperview() } var previousButton: UIButton? var currentX: CGFloat = 16 for button in tabButtons { tabScrollView.addSubview(button) // 使用固定 frame 或 SnapKit 设置位置 button.snp.makeConstraints { make in make.centerY.equalToSuperview() make.height.equalTo(36) if let prev = previousButton { make.leading.equalTo(prev.snp.trailing).offset(8) } else { make.leading.equalTo(tabScrollView.contentLayoutGuide).offset(16) } make.width.greaterThanOrEqualTo(80) } previousButton = button currentX += button.intrinsicContentSize.width + 8 } // 手动设置 contentSize(更稳定) DispatchQueue.main.async { var totalWidth: CGFloat = 16 for (i, btn) in self.tabButtons.enumerated() { totalWidth += btn.intrinsicContentSize.width + (i > 0 ? 8 : 0) } totalWidth += 16 self.tabScrollView.contentSize = CGSize(width: totalWidth, height: 40) } } // MARK: - 数据模型构建(仅搭建结构,不填充真实数据) private func reloadData() { var tempSectionArray = [TPBTableSectionModel]() let section0 = TPBTableSectionModel() var cellModels = [TPBBaseTableCellModel]() // Cell 1: Tab ScrollView let tabCellModel = TPBBaseTableCellModel.customContent(with: tabScrollView) cellModels.append(tabCellModel) // Cell 2: 占位用的 CollectionView 区域(仅视觉框架) let collectionViewPlaceholder = UIView() collectionViewPlaceholder.backgroundColor = .tpbBackground collectionViewPlaceholder.layer.cornerRadius = 12 collectionViewPlaceholder.clipsToBounds = true // 添加一个简单的提示标签表示“这里是列表” let placeholderLabel = UILabel() placeholderLabel.text = "设备内容区域" placeholderLabel.textColor = .tpbTextSecondaryContent placeholderLabel.font = .tpr14Regular() placeholderLabel.textAlignment = .center placeholderLabel.sizeToFit() collectionViewPlaceholder.addSubview(placeholderLabel) placeholderLabel.snp.makeConstraints { make in make.center.equalToSuperview() } let collectionCellModel = TPBBaseTableCellModel.customContent(with: collectionViewPlaceholder) collectionCellModel.height = TPBTableElementHeight.customHeight(240) cellModels.append(collectionCellModel) section0.cellModelArray = cellModels tempSectionArray.append(section0) sectionArray = tempSectionArray tableView.reloadData() } // MARK: - 生命周期 override func viewDidLoad() { super.viewDidLoad() reloadData() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 后续绑定 collectionView delegate } // MARK: - 点击事件 @objc private func onBack() { navigationController?.popViewController(animated: true) } @objc private func onSettings() { print("Settings tapped") } @objc private func onTabTapped(_ sender: UIButton) { guard sender.tag != selectedTabIndex else { return } tabButtons[selectedTabIndex].isSelected = false selectedTabIndex = sender.tag sender.isSelected = true // 后续刷新数据 print("Switched to tab: \(selectedTabIndex)") } private func updateTabSelection(index: Int) { for (i, btn) in tabButtons.enumerated() { btn.isSelected = (i == index) } } } // MARK: - TPBSearchBarDelegate(空实现,仅满足协议要求) extension DeviceListNewViewController: TPBSearchBarDelegate { func searchBar(_ searchBar: TPBSearchBar, textDidChange searchText: String) { // TODO: 搜索关键词变化时处理(后续接入 ViewModel) } func searchBarTextDidBeginEditing(_ searchBar: TPBSearchBar) { addTapToDismissKeyboard() } func searchBarTextDidEndEditing(_ searchBar: TPBSearchBar) { removeTapToDismissKeyboard() } func searchBarSearchButtonClicked(_ searchBar: TPBSearchBar) { searchBar.resignFirstResponder() } } // MARK: - Keyboard Dismiss Gesture private extension DeviceListNewViewController { func addTapToDismissKeyboard() { let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) objc_setAssociatedObject( self, &AssociatedKeys.searchBarTapGestureKey, tap, .OBJC_ASSOCIATION_RETAIN_NONATOMIC ) } func removeTapToDismissKeyboard() { guard let tap = objc_getAssociatedObject(self, &AssociatedKeys.searchBarTapGestureKey) as? UITapGestureRecognizer else { return } view.removeGestureRecognizer(tap) objc_setAssociatedObject(self, &AssociatedKeys.searchBarTapGestureKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } @objc func dismissKeyboard() { searchBar.resignFirstResponder() } } // MARK: - Associated Object Keys private struct AssociatedKeys { static var searchBarTapGestureKey: UInt8 = 0 }
最新发布
12-02
Cannot find 'layoutTabButtonsInScrollView' in scope Cannot find 'setupMockCollectionView' in scope Cannot find 'TPInputCheckTool' in scope 出现这三个错误 我现在里面还没有数据进去,可以先留好位置后续填写,先把页面整体的UI框架样式搭建出来,你明白我意思吗?另外不要修改我关于标题名称等写法,直接就写label = “xxx”就行。 重新修改我的代码,搭建UI框架 import UIKit import SnapKit class DeviceListNewViewController: SurveillanceCommonTableController { // MARK: - 属性 private lazy var titleView: UILabel = { let label = UILabel() label.text = "设备列表" label.font = .tpm20Medium() label.textColor = .tpbTextPrimary label.textAlignment = .center return label }() private lazy var searchBar: TPBSearchBar = { let bar = TPBSearchBar() bar.placeholder = LocalizedString(key: searchPlaceholder) bar.backgroundColor = .clear bar.delegate = self return bar }() private lazy var searchContainerView: UIView = { let view = UIView() view.backgroundColor = UIColor(white: 0.96, alpha: 1.0) view.layer.cornerRadius = 22 view.clipsToBounds = true view.addSubview(searchBar) return view }() private lazy var tabScrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.showsHorizontalScrollIndicator = false scrollView.backgroundColor = .clear scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() private lazy var tabButtons: [UIButton] = { return tabButtonTitles.enumerated().map { index, title in let btn = UIButton(type: .custom) btn.tag = index btn.setTitle(title, for: .normal) btn.titleLabel?.font = UIFont.tpr14Regular() btn.setTitleColor(.black, for: .normal) btn.setTitleColor(.tpbPrimary, for: .selected) btn.layer.borderWidth = 1 btn.layer.borderColor = UIColor(white: 0.85, alpha: 1.0).cgColor btn.layer.cornerRadius = 20 btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) btn.addTarget(self, action: #selector(onTabTapped(_:)), for: .touchUpInside) return btn } }() private let tabButtonTitles = ["所有设备","收藏页面","站点选择"] private var selectedTabIndex = 0 // MARK: - View Setup override func tpbSetupSubviews() { super.tpbSetupSubviews() setupNav() view.addSubview(titleView) view.addSubview(searchContainerView) // 添加外层容器 view.addSubview(tabScrollView) updateTabSelection(index: selectedTabIndex) } private func setupNav() { navigationItem.leftBarButtonItem = tpbCreateLeftBarButtonItem( with: TPImageLiteral("icon_back"), andTarget: self, andAction: #selector(onBack) ) navigationItem.rightBarButtonItem = tpbCreateRightBarButtonItem( with: TPImageLiteral("icon_settings"), andTarget: self, andAction: #selector(onSettings) ) navigationItem.title = "" } override func tpbMakeConstraint() { super.tpbMakeConstraint() titleView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(8) make.centerX.equalToSuperview() } searchContainerView.snp.makeConstraints { make in make.top.equalTo(titleView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(16) make.height.equalTo(searchBar.preferredHeight() + 12) // 上下 padding } searchBar.snp.makeConstraints { make in make.edges.equalTo(searchContainerView).inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) } tabScrollView.snp.makeConstraints { make in make.top.equalTo(searchContainerView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(0) make.height.equalTo(40) } layoutTabButtonsInScrollView() } // MARK: - 数据模型构建 private func reloadData() { var tempSectionArray = [TPBTableSectionModel]() let section0 = TPBTableSectionModel() var cellModels = [TPBBaseTableCellModel]() let tabCellModel = TPBBaseTableCellModel.customContent(with: tabScrollView) cellModels.append(tabCellModel) let collectionViewPlaceholder = UIView() collectionViewPlaceholder.backgroundColor = .tpbBackground collectionViewPlaceholder.layer.cornerRadius = 12 collectionViewPlaceholder.clipsToBounds = true setupMockCollectionView(in: collectionViewPlaceholder) let collectionCellModel = TPBBaseTableCellModel.customContent(with: collectionViewPlaceholder) collectionCellModel.height = TPBTableElementHeight.customHeight(240) cellModels.append(collectionCellModel) section0.cellModelArray = cellModels tempSectionArray.append(section0) sectionArray = tempSectionArray tableView.reloadData() } // MARK: - 点击事件 @objc private func onBack() { navigationController?.popViewController(animated: true) } @objc private func onSettings() { print("Settings tapped") } @objc private func onTabTapped(_ sender: UIButton) { guard sender.tag != selectedTabIndex else { return } tabButtons[selectedTabIndex].isSelected = false selectedTabIndex = sender.tag sender.isSelected = true notifyCollectionToUpdate(tabIndex: selectedTabIndex) } private func notifyCollectionToUpdate(tabIndex: Int) { print("Switched to tab: \(tabIndex)") } private func updateTabSelection(index: Int) { for (i, btn) in tabButtons.enumerated() { btn.isSelected = (i == index) } } } // MARK: - TPBSearchBarDelegate extension DeviceListNewViewController: TPBSearchBarDelegate { // 文本变化时通知(可用于防抖搜索) func searchBar(_ searchBar: TPBSearchBar, textDidChange searchText: String) { let trimmedText = TPInputCheckTool.trimSpaceString(searchText) print("搜索关键词更新: $trimmedText)") // 可在此触发请求或传递给 ViewModel } // 开始编辑:添加点击手势隐藏键盘 func searchBarTextDidBeginEditing(_ searchBar: TPBSearchBar) { addTapToDismissKeyboard() } // 结束编辑:移除手势 func searchBarTextDidEndEditing(_ searchBar: TPBSearchBar) { removeTapToDismissKeyboard() } // 搜索按钮点击:主动收起键盘 func searchBarSearchButtonClicked(_ searchBar: TPBSearchBar) { searchBar.resignFirstResponder() } } // MARK: - Keyboard Dismiss Gesture private extension DeviceListNewViewController { func addTapToDismissKeyboard() { let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) // 存储 gesture 使用 associatedObject 或 weak var(此处简化) objc_setAssociatedObject(self, &AssociatedKeys.tapGesture, tap, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } func removeTapToDismissKeyboard() { if let tap = objc_getAssociatedObject(self, &AssociatedKeys.tapGesture) as? UITapGestureRecognizer { view.removeGestureRecognizer(tap) objc_setAssociatedObject(self, &AssociatedKeys.tapGesture, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } @objc func dismissKeyboard() { searchBar.resignFirstResponder() } } // MARK: - Associated Keys private struct AssociatedKeys { static var tapGesture = "tapGesture" }
12-02
我现在要继承自同一个组件库TPBSearchBar,按照上述那样的方式对我这里面的searchbar相关部分进行同样的处理, import UIKit import SnapKit class DeviceListNewViewController: SurveillanceCommonTableController { // MARK: - 属性 private lazy var titleView: UILabel = { let label = UILabel() label.text = "设备列表" label.font = .tpm20Medium() // 使用组件库字体规范 label.textColor = .tpbTextPrimary label.textAlignment = .center return label }() private lazy var searchBar: UISearchBar = { let bar = UISearchBar() bar.placeholder = LocalizedString(key: searchPlaceholder) bar.barTintColor = UIColor(white: 0.96, alpha: 1.0) bar.isTranslucent = false bar.searchBarStyle = .prominent bar.layer.cornerRadius = 22 bar.clipsToBounds = true bar.backgroundColor = .clear return bar }() private lazy var tabScrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.showsHorizontalScrollIndicator = false scrollView.backgroundColor = .clear scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() private lazy var tabButtons: [UIButton] = { return tabButtonTitles.enumerated().map { index, title in let btn = UIButton(type: .custom) btn.tag = index btn.setTitle(title, for: .normal) btn.titleLabel?.font = UIFont.tpr14Regular() btn.setTitleColor(.blue, for: .normal) btn.setTitleColor(.tpbPrimary, for: .selected) btn.layer.borderWidth = 1 btn.layer.borderColor = UIColor(white: 0.85, alpha: 1.0).cgColor btn.layer.cornerRadius = 20 btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) btn.addTarget(self, action: #selector(onTabTapped(_:)), for: .touchUpInside) return btn } }() private let tabButtonTitles = ["所有设备","收藏页面","站点选择"] private var selectedTabIndex = 0 // MARK: - View override func tpbSetupSubviews() { super.tpbSetupSubviews() setupNav() view.addSubview(titleView) view.addSubview(searchBar) view.addSubview(tabScrollView) // 初始化 tab 按钮 updateTabSelection(index: selectedTabIndex) } private func setupNav() { // 使用组件库封装的方法创建左右按钮(更安全) navigationItem.leftBarButtonItem = tpbCreateLeftBarButtonItem( with: TPImageLiteral("icon_back"), andTarget: self, andAction: #selector(onBack) ) navigationItem.rightBarButtonItem = tpbCreateRightBarButtonItem( with: TPImageLiteral("icon_settings"), andTarget: self, andAction: #selector(onSettings) ) navigationItem.title = "" } override func tpbMakeConstraint() { super.tpbMakeConstraint() titleView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(8) make.centerX.equalToSuperview() } searchBar.snp.makeConstraints { make in make.top.equalTo(titleView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(16) make.height.equalTo(44) } tabScrollView.snp.makeConstraints { make in make.top.equalTo(searchBar.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(0) make.height.equalTo(40) } // 布局 tab 按钮到 scrollview layoutTabButtonsInScrollView() } private func layoutTabButtonsInScrollView() { // 移除旧的 subviews 防止重复添加 tabScrollView.subviews.forEach { $0.removeFromSuperview() } var previousButton: UIButton? var totalWidth: CGFloat = 16 for (index, button) in tabButtons.enumerated() { tabScrollView.addSubview(button) button.snp.makeConstraints { make in make.centerY.equalToSuperview() make.height.equalTo(40) if let prev = previousButton { make.leading.equalTo(prev.snp.trailing).offset(8) } else { make.leading.equalTo(tabScrollView.contentLayoutGuide).offset(16) } make.width.greaterThanOrEqualTo(80) // 最小宽度 } // 异步测量以更新 contentSize DispatchQueue.main.async { totalWidth += button.intrinsicContentSize.width + (index > 0 ? 8 : 0) if index == self.tabButtons.count - 1 { self.tabScrollView.contentSize = CGSize(width: totalWidth + 16, height: 40) } } previousButton = button } } override func viewDidLoad() { super.viewDidLoad() searchBar.delegate = self reloadData() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) bindCollectionViewDelegates() } // MARK: - 数据模型构建 private func reloadData() { var tempSectionArray = [TPBTableSectionModel]() // Section 0: 内容区域 let section0 = TPBTableSectionModel() var cellModels = [TPBBaseTableCellModel]() // Cell 1: Tab ScrollView let tabCellModel = TPBBaseTableCellModel.customContent(with: tabScrollView) cellModels.append(tabCellModel) // Cell 2: 占位 Collection 内容区(后续替换为真实 UICollectionView) let collectionViewPlaceholder = UIView() collectionViewPlaceholder.backgroundColor = .tpbBackground collectionViewPlaceholder.layer.cornerRadius = 12 collectionViewPlaceholder.clipsToBounds = true // 立即配置其子视图(不需要延迟或闭包) setupMockCollectionView(in: collectionViewPlaceholder) // 使用 correct API: customContent(with:) let collectionCellModel = TPBBaseTableCellModel.customContent(with: collectionViewPlaceholder) collectionCellModel.height = TPBTableElementHeight.customHeight(240) // 设置固定高度 section0.cellModelArray = cellModels tempSectionArray.append(section0) sectionArray = tempSectionArray tableView.reloadData() } private func setupMockCollectionView(in container: UIView) { // 未来接入真正的 UICollectionView 或 Compositional Layout // 现在先加个子视图示意 let label = UILabel() label.text = "设备列表占位区域" label.textAlignment = .center label.textColor = .tpbTextSecondaryContent label.font = .tpr14Regular() label.sizeToFit() container.addSubview(label) label.snp.makeConstraints { make in make.center.equalToSuperview() } } // MARK: - 点击事件 @objc private func onBack() { navigationController?.popViewController(animated: true) } @objc private func onSettings() { print("Settings tapped") // TODO: 跳转设置页 } @objc private func onTabTapped(_ sender: UIButton) { guard sender.tag != selectedTabIndex else { return } tabButtons[selectedTabIndex].isSelected = false selectedTabIndex = sender.tag sender.isSelected = true notifyCollectionToUpdate(tabIndex: selectedTabIndex) } private func notifyCollectionToUpdate(tabIndex: Int) { print("Switched to tab: \(tabIndex)") // TODO: 根据 tabIndex 刷新 collectionView 数据 } private func bindCollectionViewDelegates() { // TODO: 绑定 UICollectionView 的 delegate & dataSource } private func updateTabSelection(index: Int) { for (i, btn) in tabButtons.enumerated() { btn.isSelected = (i == index) } } } // MARK: - UISearchBarDelegate extension DeviceListNewViewController: UISearchBarDelegate { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() } }
12-02
我测试了一下,取消掉 super.tpbMakeConstraint()的注释,所有的view都能被加载,但是设备列表、scrollview、searchbar都叠到了一起,请仔细分析重新生成完整代码 import UIKit import SnapKit class DeviceListNewViewController: SurveillanceCommonTableController { // MARK: - 属性 private lazy var titleContainerView: UIView = { let view = UIView() view.backgroundColor = .red return view }() private lazy var titleLabel: UILabel = { let label = UILabel() label.text = "设备列表" label.font = .tpm20Medium() label.textColor = .tpbTextPrimary label.textAlignment = .center label.numberOfLines = 1 return label }() private lazy var searchBar: TPBSearchBar = { let bar = TPBSearchBar() bar.placeholder = "搜索" bar.backgroundColor = .clear bar.delegate = self return bar }() private lazy var searchContainerView: UIView = { let view = UIView() view.backgroundColor = UIColor(white: 0.96, alpha: 1.0) view.layer.cornerRadius = 22 view.clipsToBounds = true view.addSubview(searchBar) return view }() private lazy var tabScrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.showsHorizontalScrollIndicator = false scrollView.backgroundColor = .clear scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() private lazy var tabButtons: [UIButton] = { return tabButtonTitles.enumerated().map { index, title in let btn = UIButton(type: .custom) btn.tag = index btn.setTitle(title, for: .normal) btn.titleLabel?.font = UIFont.tpr14Regular() btn.setTitleColor(.black, for: .normal) btn.setTitleColor(.tpbPrimary, for: .selected) btn.layer.borderWidth = 1 btn.layer.borderColor = UIColor(white: 0.85, alpha: 1.0).cgColor btn.layer.cornerRadius = 20 btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) btn.addTarget(self, action: #selector(onTabTapped(_:)), for: .touchUpInside) return btn } }() private let tabButtonTitles = ["所有设备", "收藏页面", "站点选择"] private var selectedTabIndex = 0 // MARK: - UICollectionView private var collectionView: UICollectionView! // MARK: - View Setup override func tpbSetupSubviews() { super.tpbSetupSubviews() setupNav() setupCollectionView() view.addSubviews([ titleContainerView, searchContainerView, tabScrollView, tableView ]) titleContainerView.addSubview(titleLabel) searchContainerView.addSubview(searchBar) updateTabSelection(index: selectedTabIndex) layoutTabButtonsInScrollView() } private func setupNav() { navigationItem.leftBarButtonItem = tpbCreateLeftBarButtonItem( with: TPImageLiteral("icon_back"), andTarget: self, andAction: #selector(onBack) ) navigationItem.rightBarButtonItem = tpbCreateRightBarButtonItem( with: TPImageLiteral("icon_settings"), andTarget: self, andAction: #selector(onSettings) ) navigationItem.title = "" } private func setupCollectionView() { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical layout.minimumLineSpacing = 10 layout.minimumInteritemSpacing = 10 layout.sectionInset = UIEdgeInsets(top: 10, left: 16, bottom: 10, right: 16) collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.backgroundColor = .tpbBackground collectionView.alwaysBounceVertical = true collectionView.layer.cornerRadius = 12 collectionView.clipsToBounds = true // 注册 cell(假设使用默认 UICollectionViewCell) collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "DeviceCell") } override func tpbMakeConstraint() { super.tpbMakeConstraint() titleContainerView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(8) make.leading.trailing.equalToSuperview().inset(16) make.height.equalTo(40) } titleLabel.snp.makeConstraints { make in make.center.equalToSuperview() make.leading.greaterThanOrEqualToSuperview().offset(20) make.trailing.lessThanOrEqualToSuperview().offset(-20) } searchContainerView.snp.makeConstraints { make in make.top.equalTo(titleContainerView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(16) make.height.equalTo(44) } searchBar.snp.makeConstraints { make in make.edges.equalTo(searchContainerView).inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) } tabScrollView.snp.makeConstraints { make in make.top.equalTo(searchContainerView.snp.bottom).offset(16) make.leading.trailing.equalToSuperview().inset(0) make.height.equalTo(40) } tableView.snp.remakeConstraints { make in make.top.equalTo(tabScrollView.snp.bottom) make.leading.trailing.equalToSuperview() make.bottom.equalTo(view.safeAreaLayoutGuide) } } // MARK: - 内联布局 Tab 按钮 private func layoutTabButtonsInScrollView() { tabScrollView.subviews.forEach { $0.removeFromSuperview() } var previousButton: UIButton? for button in tabButtons { tabScrollView.addSubview(button) button.snp.makeConstraints { make in make.centerY.equalToSuperview() make.height.equalTo(36) if let prev = previousButton { make.leading.equalTo(prev.snp.trailing).offset(8) } else { make.leading.equalTo(tabScrollView.contentLayoutGuide).offset(16) } make.width.greaterThanOrEqualTo(80) } previousButton = button } // 手动设置 contentSize DispatchQueue.main.async { var totalWidth: CGFloat = 16 for (i, btn) in self.tabButtons.enumerated() { totalWidth += btn.intrinsicContentSize.width + (i > 0 ? 8 : 0) } totalWidth += 16 self.tabScrollView.contentSize = CGSize(width: totalWidth, height: 40) } } // MARK: - 数据模型构建:现在把 UICollectionView 放入 cell private func reloadData() { var tempSectionArray = [TPBTableSectionModel]() // Section 0: 包含 titleView(已添加到主 view)、searchBar、tabScrollView let section0 = TPBTableSectionModel() var cellModels = [TPBBaseTableCellModel]() // Cell 1: Tab ScrollView(横向滚动按钮组) let tabCellModel = TPBBaseTableCellModel.customContent(with: tabScrollView) cellModels.append(tabCellModel) // Section 0 结束 section0.cellModelArray = cellModels tempSectionArray.append(section0) // Section 1: 真实的 UICollectionView let section1 = TPBTableSectionModel() let collectionCellModel = TPBBaseTableCellModel.customContent(with: collectionView) collectionCellModel.height = TPBTableElementHeight.customHeight(500) // 固定高度,内部可滚动 section1.cellModelArray = [collectionCellModel] tempSectionArray.append(section1) // 赋值并刷新 sectionArray = tempSectionArray tableView.reloadData() } // MARK: - 生命周期 override func viewDidLoad() { super.viewDidLoad() reloadData() // 绑定数据源(必须在 reloadData 后确保 collectionView 已加入视图层级) collectionView.dataSource = self collectionView.delegate = self } // MARK: - 点击事件 @objc private func onBack() { navigationController?.popViewController(animated: true) } @objc private func onSettings() { print("Settings tapped") } @objc private func onTabTapped(_ sender: UIButton) { guard sender.tag != selectedTabIndex else { return } tabButtons[selectedTabIndex].isSelected = false selectedTabIndex = sender.tag sender.isSelected = true print("Switched to tab: \(selectedTabIndex)") // TODO: 切换 tab 时刷新 collectionView 数据 } private func updateTabSelection(index: Int) { for (i, btn) in tabButtons.enumerated() { btn.isSelected = (i == index) } } } // MARK: - UICollectionViewDataSource extension DeviceListNewViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 20 // 模拟数据 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DeviceCell", for: indexPath) cell.backgroundColor = .systemBlue return cell } } // MARK: - UICollectionViewDelegateFlowLayout extension DeviceListNewViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = (collectionView.bounds.width - 32 - 10) / 2 // 两列,间距10 return CGSize(width: width, height: 80) } } // MARK: - TPBSearchBarDelegate extension DeviceListNewViewController: TPBSearchBarDelegate { func searchBar(_ searchBar: TPBSearchBar, textDidChange searchText: String) { // 可在此触发搜索过滤逻辑 } func searchBarTextDidBeginEditing(_ searchBar: TPBSearchBar) { addTapToDismissKeyboard() } func searchBarTextDidEndEditing(_ searchBar: TPBSearchBar) { removeTapToDismissKeyboard() } func searchBarSearchButtonClicked(_ searchBar: TPBSearchBar) { searchBar.resignFirstResponder() } } // MARK: - Keyboard Dismiss Gesture private extension DeviceListNewViewController { func addTapToDismissKeyboard() { let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) objc_setAssociatedObject( self, &AssociatedKeys.searchBarTapGestureKey, tap, .OBJC_ASSOCIATION_RETAIN_NONATOMIC ) } func removeTapToDismissKeyboard() { guard let tap = objc_getAssociatedObject(self, &AssociatedKeys.searchBarTapGestureKey) as? UITapGestureRecognizer else { return } view.removeGestureRecognizer(tap) objc_setAssociatedObject(self, &AssociatedKeys.searchBarTapGestureKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } @objc func dismissKeyboard() { searchBar.resignFirstResponder() } } // MARK: - Associated Object Keys private struct AssociatedKeys { static var searchBarTapGestureKey: UInt8 = 0 } 同时我再发给你另一个同组件库的代码参考:import UIKit class AddOrganizationCheckDetailViewController: SurveillanceCommonTableController { // MARK: - 属性 private lazy var segmentControl: TPBSegmentedControl = { let segment = TPBSegmentedControl(segmentedStyle: .roundRect, itemArray: [LocalizedString(key: addOrganizationEssentialOrganization),LocalizedString(key: addOrganizationStandardOrganization)], initialIndex: 0) segment.indexDidChangeCallback = { [weak self] _ in self?.reloadView() } return segment }() private lazy var checkDetailView: AddOrganizationCheckDetailView = { let view = AddOrganizationCheckDetailView() view.updateWith(orgCategory: .essential) return view }() convenience init(orgCategory: TPSSVMSOrgCategory) { self.init() if orgCategory == .essential { self.segmentControl.selectedIndex = 0 } else { self.segmentControl.selectedIndex = 1 } } deinit { print("AddOrganizationCheckDetailViewController deinit") } // MARK: - View override func tpbSetupSubviews() { super.tpbSetupSubviews() setupNav() view.addSubview(segmentControl) } private func setupNav() { navigationItem.leftBarButtonItem = nil navigationItem.rightBarButtonItem = tpbCreateRightBarButtonItem(with: TPImageLiteral("common_close"), andTarget: self, andAction: #selector(clickBack)) navigationItem.title = LocalizedString(key: addOrganizationSelectOrgDetail) } override func tpbMakeConstraint() { // 暂不执行super不然会显示不了segment // super.tpbMakeConstraint() segmentControl.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(8) make.leading.equalTo(view.safeAreaLayoutGuide).offset(16) make.trailing.equalTo(view.safeAreaLayoutGuide).offset(-16) make.height.equalTo(32) } tableView.snp.remakeConstraints { make in make.top.equalTo(segmentControl.snp.bottom) make.leading.trailing.equalTo(view.safeAreaLayoutGuide) make.bottom.equalTo(view) } } override func viewDidLoad() { super.viewDidLoad() reloadView() } private func reloadView() { reloadData() } // MARK: - dateModel private func reloadData() { var tempSectionArray = [TPBTableSectionModel]() // section0 let section0 = TPBTableSectionModel() var section0CellModelArray = [TPBBaseTableCellModel]() if segmentControl.selectedIndex == 0 { checkDetailView.updateWith(orgCategory: .essential) } else { checkDetailView.updateWith(orgCategory: .standard) } let detailCellModel = TPBBaseTableCellModel.customContent(with: checkDetailView) section0CellModelArray.append(detailCellModel) section0.cellModelArray = section0CellModelArray tempSectionArray.append(section0) sectionArray = tempSectionArray } // MARK: - 点击事件 @objc private func clickBack() { dismiss(animated: true) } } // 自定义view fileprivate class AddOrganizationCheckDetailLabel: TPBBaseView { // MARK: - 属性 private lazy var dotImageView: UIImageView = { let view = UIImageView(image: TPImageLiteral("thirdParty_dot_gray")) view.contentMode = .scaleAspectFit return view }() private lazy var titleLabel: UILabel = { let label = UILabel() label.numberOfLines = 0 label.font = .tpr14Regular() label.textColor = .tpbTextSecondaryContent label.textAlignment = .left label.lineBreakMode = .byWordWrapping return label }() // MARK: - View override func setupSubviews() { super.setupSubviews() backgroundColor = .clear addSubviews([dotImageView, titleLabel]) } override func makeConstraint() { super.makeConstraint() dotImageView.snp.makeConstraints { make in make.leading.equalToSuperview() make.top.equalToSuperview().offset(4) make.height.width.equalTo(8) } titleLabel.snp.makeConstraints { make in make.leading.equalTo(dotImageView.snp.trailing).offset(8) make.top.trailing.bottom.equalToSuperview() } } // MARK: - 更新函数 func updateWith(orgCategory: TPSSVMSOrgCategory, title: String) { if orgCategory == .essential { dotImageView.image = TPImageLiteral("thirdParty_dot_gray") } else { dotImageView.image = TPImageLiteral("number_diot") } titleLabel.text = title } } fileprivate class AddOrganizationCheckDetailView: TPBBaseView { // MARK: - 属性 private lazy var containerView: UIView = { let view = UIView() view.backgroundColor = .tpbCard view.layer.cornerRadius = 10 view.layer.masksToBounds = true return view }() private lazy var gradientLayer: CAGradientLayer = { // 加入底色 let layer = CAGradientLayer() layer.frame = CGRectMake(containerView.bounds.minX, containerView.bounds.minY, containerView.bounds.size.width, 112) layer.startPoint = CGPoint(x: 0, y: 0) layer.endPoint = CGPoint(x: 0, y: 1) layer.colors = [UIColor.tpbGreenLight.cgColor, UIColor.clear.cgColor] layer.isHidden = true return layer }() private lazy var rightLabelContainerView: UIView = { let view = UIView() view.backgroundColor = .tpbBlueLight view.layer.cornerRadius = 3 view.layer.maskedCorners = [.layerMinXMaxYCorner] return view }() private lazy var rightLabel: UILabel = { let label = UILabel() label.text = LocalizedString(key: addOrganizationSelectOrgFree) label.numberOfLines = 1 label.font = .tpr14Regular() label.textColor = .tpbBlue label.textAlignment = .left label.lineBreakMode = .byWordWrapping return label }() private lazy var titleLabel: UILabel = { let label = UILabel() label.numberOfLines = 0 label.font = .tpm20Medium() label.textColor = .tpbTextPrimary label.textAlignment = .center label.lineBreakMode = .byWordWrapping return label }() private lazy var subTitleLabel: UILabel = { let label = UILabel() label.text = LocalizedString(key: addOrganizationSelectOrgLicenseNeeded) label.numberOfLines = 0 label.font = .tpr16Regular() label.textColor = .tpbTextPrimary label.textAlignment = .center label.lineBreakMode = .byWordWrapping return label }() private lazy var networkImageView: UIImageView = { let view = UIImageView(image: TPImageLiteral("central_network_dis")) view.contentMode = .scaleAspectFit return view }() private lazy var networkLabel: UILabel = { let label = UILabel() label.text = LocalizedString(key: addOrganizationOmadaNetwork) label.numberOfLines = 0 label.font = .tpm16Medium() label.textColor = .tpbTextPrimary label.textAlignment = .left label.lineBreakMode = .byWordWrapping return label }() private lazy var guardImageView: UIImageView = { let view = UIImageView(image: TPImageLiteral("central_surveillance_dis")) view.contentMode = .scaleAspectFit return view }() private lazy var guardLabel: UILabel = { let label = UILabel() label.text = LocalizedString(key: shareSocialPlatformWebDetail) label.numberOfLines = 0 label.font = .tpm16Medium() label.textColor = .tpbTextPrimary label.textAlignment = .left label.lineBreakMode = .byWordWrapping return label }() private lazy var essentialPart1LabelList: [AddOrganizationCheckDetailLabel] = { var list = [AddOrganizationCheckDetailLabel]() for str in [LocalizedString(key: addOrganizationSelectOrgDetailPart1_Tip1), LocalizedString(key: addOrganizationSelectOrgDetailPart1_Tip2)] { let view = AddOrganizationCheckDetailLabel() view.updateWith(orgCategory: .essential, title: str) list.append(view) } return list }() private lazy var essentialPart2LabelList: [AddOrganizationCheckDetailLabel] = { var list = [AddOrganizationCheckDetailLabel]() for str in [LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Essential_Tip1), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Essential_Tip2), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Essential_Tip3), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Essential_Tip4), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Essential_Tip5)] { let view = AddOrganizationCheckDetailLabel() view.updateWith(orgCategory: .essential, title: str) list.append(view) } return list }() private lazy var essentialPart3LabelList: [AddOrganizationCheckDetailLabel] = { var list = [AddOrganizationCheckDetailLabel]() for str in [LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip1), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip2), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip3), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip4), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip5), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip6), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Essential_Tip7)] { let view = AddOrganizationCheckDetailLabel() view.updateWith(orgCategory: .essential, title: str) list.append(view) } return list }() private lazy var standardPart1LabelList: [AddOrganizationCheckDetailLabel] = { var list = [AddOrganizationCheckDetailLabel]() for str in [LocalizedString(key: addOrganizationSelectOrgDetailPart1_Tip1), LocalizedString(key: addOrganizationSelectOrgDetailPart1_Tip2)] { let view = AddOrganizationCheckDetailLabel() view.updateWith(orgCategory: .standard, title: str) list.append(view) } return list }() private lazy var standardPart2LabelList: [AddOrganizationCheckDetailLabel] = { var list = [AddOrganizationCheckDetailLabel]() for str in [LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Standard_Tip1), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Standard_Tip2), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Standard_Tip3), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Standard_Tip4), LocalizedString(key: addOrganizationSelectOrgDetailNetwork_Standard_Tip5)] { let view = AddOrganizationCheckDetailLabel() view.updateWith(orgCategory: .standard, title: str) list.append(view) } return list }() private lazy var standardPart3LabelList: [AddOrganizationCheckDetailLabel] = { var list = [AddOrganizationCheckDetailLabel]() for str in [LocalizedString(key: addOrganizationSelectOrgDetailGuard_Standard_Tip1), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Standard_Tip2), LocalizedString(key: addOrganizationSelectOrgDetailGuard_Standard_Tip3)] { let view = AddOrganizationCheckDetailLabel() view.updateWith(orgCategory: .standard, title: str) list.append(view) } return list }() private lazy var part1StackView: UIStackView = { let view = UIStackView() view.axis = .vertical view.alignment = .leading view.spacing = 12 view.distribution = .equalSpacing return view }() private lazy var part2StackView: UIStackView = { let view = UIStackView() view.axis = .vertical view.alignment = .leading view.spacing = 12 view.distribution = .equalSpacing return view }() private lazy var part3StackView: UIStackView = { let view = UIStackView() view.axis = .vertical view.alignment = .leading view.spacing = 12 view.distribution = .equalSpacing return view }() // MARK: - View override func setupSubviews() { super.setupSubviews() addSubview(containerView) containerView.addSubviews([rightLabelContainerView, titleLabel, subTitleLabel, networkImageView, networkLabel, guardImageView, guardLabel, part1StackView, part2StackView, part3StackView]) rightLabelContainerView.addSubview(rightLabel) containerView.layer.addSublayer(gradientLayer) } override func makeConstraint() { super.makeConstraint() containerView.snp.remakeConstraints { make in make.edges.equalToSuperview() } rightLabelContainerView.snp.remakeConstraints { make in make.trailing.top.equalToSuperview() } rightLabel.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(13) make.trailing.equalToSuperview().offset(-13) make.top.equalToSuperview().offset(2) make.bottom.equalToSuperview().offset(-2) } titleLabel.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(16) make.trailing.equalToSuperview().offset(-16) make.top.equalToSuperview().offset(44) } subTitleLabel.snp.remakeConstraints { make in make.leading.trailing.equalTo(titleLabel) make.top.equalTo(titleLabel.snp.bottom).offset(8) } part1StackView.snp.remakeConstraints { make in make.leading.trailing.equalTo(titleLabel) if subTitleLabel.isHidden { make.top.equalTo(titleLabel.snp.bottom).offset(24) } else { make.top.equalTo(subTitleLabel.snp.bottom).offset(24) } } networkImageView.snp.remakeConstraints { make in make.leading.equalTo(titleLabel) make.centerY.equalTo(networkLabel) make.height.width.equalTo(18) } networkLabel.snp.remakeConstraints { make in make.leading.equalTo(networkImageView.snp.trailing).offset(8) make.trailing.equalTo(titleLabel) make.top.equalTo(part1StackView.snp.bottom).offset(24) } part2StackView.snp.remakeConstraints { make in make.leading.trailing.equalTo(titleLabel) make.top.equalTo(networkLabel.snp.bottom).offset(16) } guardImageView.snp.remakeConstraints { make in make.leading.equalTo(titleLabel) make.centerY.equalTo(guardLabel) make.height.width.equalTo(18) } guardLabel.snp.remakeConstraints { make in make.leading.equalTo(guardImageView.snp.trailing).offset(8) make.trailing.equalTo(titleLabel) make.top.equalTo(part2StackView.snp.bottom).offset(24) } part3StackView.snp.remakeConstraints { make in make.leading.trailing.equalTo(titleLabel) make.top.equalTo(guardLabel.snp.bottom).offset(16) make.bottom.equalToSuperview().offset(-24) } } // MARK: - 更新函数 func updateWith(orgCategory: TPSSVMSOrgCategory) { if orgCategory == .essential { gradientLayer.isHidden = true rightLabel.text = LocalizedString(key: addOrganizationSelectOrgFree) rightLabel.textColor = .tpbBlue rightLabelContainerView.backgroundColor = .tpbBlueLight titleLabel.text = LocalizedString(key: orgCategoryEssentials) subTitleLabel.isHidden = true networkImageView.image = TPImageLiteral("central_network_dis") guardImageView.image = TPImageLiteral("central_surveillance_dis") } else { gradientLayer.isHidden = false rightLabel.text = LocalizedString(key: addOrganizationSelectOrgLicense) rightLabel.textColor = .tpbTextWhite rightLabelContainerView.backgroundColor = .tpbPrimary titleLabel.text = LocalizedString(key: deviceSettingSmartWhiteLampModeAutoWTL) subTitleLabel.isHidden = false networkImageView.image = TPImageLiteral("central_network") guardImageView.image = TPImageLiteral("central_surveillance") } configStackView(orgCategory: orgCategory) makeConstraint() } override func layoutSubviews() { super.layoutSubviews() gradientLayer.frame = CGRectMake(containerView.bounds.minX, containerView.bounds.minY, containerView.bounds.size.width, 112) } private func configStackView(orgCategory: TPSSVMSOrgCategory) { for view in essentialPart1LabelList { view.removeFromSuperview() } for view in essentialPart2LabelList { view.removeFromSuperview() } for view in essentialPart3LabelList { view.removeFromSuperview() } for view in standardPart1LabelList { view.removeFromSuperview() } for view in standardPart2LabelList { view.removeFromSuperview() } for view in standardPart3LabelList { view.removeFromSuperview() } if orgCategory == .essential { for view in essentialPart1LabelList { part1StackView.addArrangedSubview(view) } for view in essentialPart2LabelList { part2StackView.addArrangedSubview(view) } for view in essentialPart3LabelList { part3StackView.addArrangedSubview(view) } } else { for view in standardPart1LabelList { part1StackView.addArrangedSubview(view) } for view in standardPart2LabelList { part2StackView.addArrangedSubview(view) } for view in standardPart3LabelList { part3StackView.addArrangedSubview(view) } } } }
12-02
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值