Posts

Post marked as solved
1 Replies
Change var configuration: UIContentConfiguration to var configuration: UIContentConfiguration { didSet { configureSubviews() } } and remove the subviews in the content view initialization: subviews.forEach { $0.removeFromSuperview() }
Post marked as solved
1 Replies
Use UIListContentConfiguration: import UIKit class ViewController: UIViewController { var collectionView: UICollectionView! var dataSource: UICollectionViewDiffableDataSource<String, String>! override func viewDidLoad() { super.viewDidLoad() configureHierarchy() configureDataSource() } func configureHierarchy() { collectionView = .init(frame: .zero, collectionViewLayout: createLayout()) view.addSubview(collectionView) collectionView.frame = view.bounds } func createLayout() -> UICollectionViewLayout { UICollectionViewCompositionalLayout { section, layoutEnvironment in let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped) return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) } } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in var contentConfig = CustomListContentConfiguration() contentConfig.placeholder = "Placeholder" cell.contentConfiguration = contentConfig } dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier) } var snapshot = NSDiffableDataSourceSnapshot<String, String>() snapshot.appendSections(["main"]) snapshot.appendItems(["demo"]) dataSource.apply(snapshot, animatingDifferences: false) } } class CustomListContentConfiguration: UIContentConfiguration { var placeholder: String? func makeContentView() -> UIView & UIContentView { return CustomListContentView(configuration: self) } func updated(for state: UIConfigurationState) -> Self { // Not handling state changes in this example, so just return self return self } } class CustomListContentView: UIView, UIContentView { var configuration: UIContentConfiguration init(configuration: UIContentConfiguration) { self.configuration = configuration super.init(frame: .zero) configureSubviews() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configureSubviews() { guard let config = configuration as? CustomListContentConfiguration else { return } let leadingView = UIView() leadingView.backgroundColor = .systemRed let textField = UITextField() textField.placeholder = config.placeholder textField.font = .systemFont(ofSize: 100) addSubview(leadingView) addSubview(textField) leadingView.translatesAutoresizingMaskIntoConstraints = false textField.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ leadingView.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor), leadingView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), leadingView.widthAnchor.constraint(equalTo: layoutMarginsGuide.heightAnchor), leadingView.heightAnchor.constraint(equalTo: layoutMarginsGuide.heightAnchor), textField.topAnchor.constraint(equalTo: topAnchor), textField.bottomAnchor.constraint(equalTo: bottomAnchor), textField.leadingAnchor.constraint(equalTo: leadingView.trailingAnchor, constant: 16), textField.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), textField.heightAnchor.constraint(greaterThanOrEqualToConstant: 44) ]) } }
Post not yet marked as solved
1 Replies
If you use cell registrations instead of supplementary registrations, the keyboard doesn't dismiss for any reason and you can also get rid of the dispatch blocks: import UIKit class ViewController: UIViewController { let words = ["foo", "bar"] var filteredWords = ["foo", "bar"] { didSet { dataSource.apply(self.snapshot) } } var collectionView: UICollectionView! var dataSource: UICollectionViewDiffableDataSource<String, String>! var snapshot: NSDiffableDataSourceSnapshot<String, String> { var snapshot = NSDiffableDataSourceSnapshot<String, String>() snapshot.appendSections(["main"]) snapshot.appendItems(["search bar id"]) snapshot.appendItems(filteredWords) return snapshot } override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = .init(title: "Apply", style: .plain, target: self, action: #selector(apply)) configureHierarchy() configureDataSource() } @objc func apply() { dataSource.apply(self.snapshot) } func configureHierarchy() { collectionView = .init(frame: .zero, collectionViewLayout: createLayout()) view.addSubview(collectionView) collectionView.frame = view.bounds collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] } func createLayout() -> UICollectionViewLayout { UICollectionViewCompositionalLayout { section, layoutEnvironment in var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped) config.headerMode = .firstItemInSection return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) } } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { _, _, _ in } let searchBarCellRegistration = UICollectionView.CellRegistration<SearchBarCell, String>{ cell, indexPath, itemIdentifier in cell.searchBar.delegate = self } dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in if indexPath.row == 0 { collectionView.dequeueConfiguredReusableCell(using: searchBarCellRegistration, for: indexPath, item: itemIdentifier) } else { collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier) } } dataSource.apply(self.snapshot, animatingDifferences: false) } } extension ViewController: UISearchBarDelegate { func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { filteredWords = words.filter { $0.hasPrefix(searchText) } } func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { filteredWords = words } } class SearchBarCell: UICollectionViewListCell { let searchBar = UISearchBar() override init(frame: CGRect) { super.init(frame: frame) contentView.addSubview(searchBar) searchBar.pinToSuperview() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension UIView { func pin( to object: CanBePinnedTo, top: CGFloat = 0, bottom: CGFloat = 0, leading: CGFloat = 0, trailing: CGFloat = 0 ) { self.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ self.topAnchor.constraint(equalTo: object.topAnchor, constant: top), self.bottomAnchor.constraint(equalTo: object.bottomAnchor, constant: bottom), self.leadingAnchor.constraint(equalTo: object.leadingAnchor, constant: leading), self.trailingAnchor.constraint(equalTo: object.trailingAnchor, constant: trailing), ]) } func pinToSuperview( top: CGFloat = 0, bottom: CGFloat = 0, leading: CGFloat = 0, trailing: CGFloat = 0, file: StaticString = #file, line: UInt = #line ) { guard let superview = self.superview else { print(">> \(#function) failed in file: \(String.localFilePath(from: file)), at line: \(line): could not find \(Self.self).superView.") return } self.pin(to: superview, top: top, bottom: bottom, leading: leading, trailing: trailing) } func pinToSuperview(constant c: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { self.pinToSuperview(top: c, bottom: -c, leading: c, trailing: -c, file: file, line: line) } } @MainActor protocol CanBePinnedTo { var topAnchor: NSLayoutYAxisAnchor { get } var bottomAnchor: NSLayoutYAxisAnchor { get } var leadingAnchor: NSLayoutXAxisAnchor { get } var trailingAnchor: NSLayoutXAxisAnchor { get } } extension UIView: CanBePinnedTo { } extension UILayoutGuide: CanBePinnedTo { } extension String { static func localFilePath(from fullFilePath: StaticString = #file) -> Self { URL(fileURLWithPath: "\(fullFilePath)").lastPathComponent } } Basically don't use supplementary views unless absolutely necessary: it also seems that there's no declarative way to update them without losing animations (Apple's guided project "Modern Collection Views" doesn't seem to provide a solution, nor do these posts: https://stackoverflow.com/questions/78311570/how-do-i-update-a-collection-view-supplementary-view-without-giving-up-on-animat, https://forums.developer.apple.com/forums/thread/749847).
Post not yet marked as solved
1 Replies
I can't edit the post here anymore so go check out the stackoverflow.com post which is up to date: https://stackoverflow.com/questions/78373006/handle-keyboard-layout-in-ios-15-uikit-app-with-collection-view-using-the-moder
Post marked as solved
1 Replies
https://stackoverflow.com/questions/746670/how-to-lose-margin-padding-in-uitextview
Post marked as solved
1 Replies
Make a custom cell: class SwitchCell: UICollectionViewListCell { let _switch = UISwitch() override init(frame: CGRect) { super.init(frame: frame) accessories = [ .customView(configuration: .init( customView: _switch, placement: .trailing()) ) ] } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } And edit cellRegistration accordingly: let cellRegistration = UICollectionView.CellRegistration<SwitchCell, String> { [weak self] cell, indexPath, itemIdentifier in guard let self else { return } cell._switch.isOn = bool cell._switch.addTarget(self, action: #selector(toggleBool), for: .valueChanged) }
Post marked as solved
1 Replies
https://stackoverflow.com/questions/78311570/how-do-i-update-a-collection-view-supplementary-view-without-giving-up-on-animat At this time the answer is: To directly update a supplementaryView you need to know its kind and section. With your example, you could add a following didSet code to a footerText: var footerText = "Initial footer text" { didSet { guard let footer = collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: 0)) as? UICollectionViewListCell else { return } var contentConfiguration = UIListContentConfiguration.cell() contentConfiguration.text = self.footerText footer.contentConfiguration = contentConfiguration } } This way each time you change footerText, your footer will be updated. You could also move contentConfiguration update to a separate fuction, I've just copied it from your configureSupplementaryViewProvider
Post marked as solved
1 Replies
https://stackoverflow.com/questions/78284030/swift-5-10-cannot-access-property-with-a-non-sendable-type-from-non-iso/78285030#78285030 In a nutshell: call signInAnonymouslyIfNecessary() in viewDidDisappear(): avoid in general dealing with class deinitializers. But if you insist on calling signInAnonymouslyIfNecessary() in the deinitializer, you can: Mark AuthController as @MainActor Mark signInAnonymouslyIfNecessary as nonisolated Wrap signInAnonymouslyIfNecessary in a Task: @MainActor final class AuthController { nonisolated func signInAnonymouslyIfNecessary() { Task { @MainActor in /// ... } } }
Post marked as solved
2 Replies
https://stackoverflow.com/questions/78268523/how-do-i-resize-a-uicollectionviewlistcell-containing-a-uitextview.
Post marked as solved
1 Replies
https://stackoverflow.com/questions/78248735/cant-display-the-simplest-uitoolbar
Post marked as solved
1 Replies
https://stackoverflow.com/questions/78089692/swiftui-selectable-stepper-in-view-that-presents-modally
Post marked as solved
1 Replies
https://stackoverflow.com/questions/78241008/override-show-sender-of-uiviewcontroller-freezes-the-ui
Post marked as solved
1 Replies
Fixed: cell.accessories = [.disclosureIndicator(), .customView(configuration: .init(customView: UIStepper(), placement: .trailing(), reservedLayoutWidth: .actual))]
Post marked as solved
1 Replies
Answer: https://stackoverflow.com/questions/77939616/change-derived-data-location-in-xcode