Post

Replies

Boosts

Views

Activity

iOS 13 setting content inset on collection view with compositional layout causes jump
I'm working with compositional layout collection views and need to support back to iOS 13, but I'm running into a strange issue when I update the content inset of the collection view. I'm using estimated cell sizes because eventually, these cells will all house different content, so they need to be dynamic. You can see the issue here below in the video. When I press "Update" I set the bottom content inset to be 100. You can see the content jumps. Then when I start to scroll to the top, as I'm nearly there, the content jumps again to a different position in the collection view. This isn't an issue on iOS 15 or 16. On iOS 14, the content doesn't jump when I update the content insets, but it does jump to a different position in the collection view when I start scrolling after it's been updated. This issue does Here's my code below: Main view controller enum Section { case main } class ViewController: CollectionViewController { private lazy var collectionViewDataSource: UICollectionViewDiffableDataSource<Section, Int> = { let dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView) { [weak self] collectionView, indexPath, value in let cell = self?.cell(with: CollectionViewCell.self, for: indexPath, in: collectionView) cell?.configure(with: value) return cell } return dataSource }() private lazy var collectionView: UICollectionView = { let collectionViewLayout = configureChatCollectionViewLayout() let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) collectionView.translatesAutoresizingMaskIntoConstraints = false registerCell(CollectionViewCell.self, in: collectionView) return collectionView }() private lazy var updateButton: UIButton = { let button = UIButton() button.setTitle("Update", for: .normal) button.setTitleColor(.blue, for: .normal) button.addTarget(self, action: #selector(updateTapped), for: .touchUpInside) button.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ button.heightAnchor.constraint(equalToConstant: 44) ]) return button }() override func viewDidLoad() { super.viewDidLoad() setupView() setDataItems(Array(0..<100)) } // MARK: - Interface methods func setDataItems(_ values: [Int]) { var snapshot = NSDiffableDataSourceSnapshot<Section, Int>() snapshot.appendSections([.main]) snapshot.appendItems(values) collectionViewDataSource.apply(snapshot, animatingDifferences: true) } // MARK: - Private methods func setupView() { view.backgroundColor = .white view.addSubview(updateButton) view.addSubview(collectionView) NSLayoutConstraint.activate([ updateButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), updateButton.leadingAnchor.constraint(equalTo: view.leadingAnchor), updateButton.trailingAnchor.constraint(equalTo: view.trailingAnchor), collectionView.topAnchor.constraint(equalTo: updateButton.bottomAnchor), collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor) ]) } func configureChatCollectionViewLayout() -> UICollectionViewLayout { let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(1000)) let item = NSCollectionLayoutItem(layoutSize: size) let group = NSCollectionLayoutGroup.vertical(layoutSize: size, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = 16 return UICollectionViewCompositionalLayout(section: section) } @objc func updateTapped() { collectionView.contentInset = .init(top: 0, left: 0, bottom: 100, right: 0) } } Cell class CollectionViewCell: UICollectionViewCell { private lazy var textLabel: UILabel = { let label = UILabel() label.font = .preferredFont(forTextStyle: .title2) label.textColor = .black label.translatesAutoresizingMaskIntoConstraints = false return label }() override func prepareForReuse() { super.prepareForReuse() textLabel.text = nil } func configure(with value: Int) { contentView.backgroundColor = .green textLabel.text = "\(value)" contentView.addSubview(textLabel) NSLayoutConstraint.activate([ textLabel.topAnchor.constraint(equalTo: contentView.topAnchor), textLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), textLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), textLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) ]) } } UICollectionView helpers class CollectionViewController: UIViewController { func registerCell<T: UICollectionViewCell>(_ type: T.Type, in collectionView: UICollectionView) { collectionView.register(type, forCellWithReuseIdentifier: type.computedReuseIdentifier) } func cell<T: UICollectionViewCell>(with type: T.Type, for indexPath: IndexPath, in collectionView: UICollectionView) -> T { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: type.computedReuseIdentifier, for: indexPath) as? T else { assertionFailure("UICollectionViewCell cannot be cast to the intended type") return T() } return cell } } extension UICollectionViewCell { class var computedReuseIdentifier : String { "\(self)" } }
0
1
1k
Jun ’23
Xcode 15 swipe in XCUITest not strong enough
All of our XCUI tests were passing with Xcode 14, now on 15 the swipeLeft() and swipeRight() calls don't seem "strong" enough to advance a UIPageControl to the next page. I've added in the velocity parameter and set it to .fast, but it still seems to fail. Anyone have any issues with this? No idea how to solve it other than explicitly stating touch points to then drag across the screen. Seems odd
0
0
515
Aug ’23
SDK framework signing certificate expiration
Since 2023 Apple have strongly suggested signing XCFrameworks to verify their origins. This has worked perfectly fine for the last year. Seeing that our certificate was about to expire, we revoked it and created a new one which we will use to sign all future releases. However, because that first certificate has been revoked, all previous releases of our XCFramework now have invalid signatures because the certificate they used no longer exists. While an update to the latest XCFramework would solve the issue, that's not always a possibility for people with lower minimum deployment targets that can only run an older version of our XCFramework. In the wwdc video on the topic it states: When the xcframework author's signing certificate expires, Xcode is able to automatically validate that a new certificate for Apple Developer Program identities is from the same developer. Does this mean that if we had not pre-empted the expiry and instead let the certificate expire, we wouldn't have this backwards compatibility issue? The course of action we've had to take is to manually go through all of our releases for the last year and re-sign them with the latest certificate. This doesn't seem like a tenable solution each year. Looking for guidance on how to manage this situation each year.
4
0
953
Apr ’24