I have a UICollectionViewLayout grid with three columns. Each item in the column has a cell full of text. I would like all the columns to be the same height as the tallest item in the group. Using UICollectionViewCompositionalLayout I'm having a hard time getting the desired results.
I created a EqualHeightsUICollectionViewCompositionalLayout subcalss to check the cell attributes in layoutAttributesForElements and stores the largest cell height in a row. This seems to work good intially, but when the collectionview invalidates, the cell sizes are not always correct. How can I fix this?
Here is an example project, and here is a stack overflow post
class EqualHeightsUICollectionViewCompositionalLayout: UICollectionViewCompositionalLayout{
var largestDict: [Int: CGFloat] = [:]
let columns = 3
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
if let attributes = attributes {
for attribute in attributes {
let height = attribute.frame.height
let row = attribute.indexPath.row / columns
if height > 1 {
self.largestDict[row] = max(height, largestDict[row] ?? 0)
}
}
}
return attributes
}
override func invalidateLayout() {
super.invalidateLayout()
largestDict.removeAll()
}
}
class TextCell: UICollectionViewCell {
let label = UILabel()
let bottomLabel = UILabel()
let container = UIView()
weak var collectionView: UICollectionView?
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("not implemented")
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let attribute = super.preferredLayoutAttributesFitting(layoutAttributes)
if let layout = collectionView?.collectionViewLayout as? EqualHeightsUICollectionViewCompositionalLayout{
let row = attribute.indexPath.row / layout.columns
if let height = layout.largestDict[row] {
attribute.frame = .init(origin: attribute.frame.origin, size: .init(width: attribute.frame.width, height: height))
}
}
return attribute
}
private func configure() {
label.numberOfLines = 0
label.font = UIFont.preferredFont(forTextStyle: .title1)
label.backgroundColor = .systemPurple
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
label.setContentHuggingPriority(.defaultHigh, for: .vertical)
bottomLabel.numberOfLines = 0
bottomLabel.font = UIFont.preferredFont(forTextStyle: .title1)
bottomLabel.text = "Bottom of cell"
bottomLabel.backgroundColor = .systemRed
bottomLabel.textColor = .white
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
bottomLabel.setContentHuggingPriority(.defaultLow, for: .vertical)
contentView.addSubview(label)
contentView.addSubview(bottomLabel)
backgroundColor = .systemBlue.withAlphaComponent(0.75)
let inset = CGFloat(0)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: inset),
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -inset),
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: inset),
bottomLabel.leadingAnchor.constraint(equalTo: label.leadingAnchor),
bottomLabel.trailingAnchor.constraint(equalTo: label.trailingAnchor),
bottomLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: inset),
bottomLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -inset),
])
}
}
func createLayout() -> UICollectionViewLayout {
let spacing = CGFloat(10)
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(1))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
return EqualHeightsUICollectionViewCompositionalLayout(section: section)
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Using the App Store Connect API how can you get the release date for an app? I've been able to use this endpoint to list a bunch of information, however the release date is not included.
As you can see in the JSON response posted below, it does have a "createdDate" but this corresponds to when the version was made in App Store Connect (Prepare for Submission), not when it was released to the store. This can be verified by looking in App Store connect.
JSON Response:
https://api.appstoreconnect.apple.com/v1/apps/395389919/appStoreVersions?limit=1
{
"data": [
{
"type": "appStoreVersions",
"id": "a75acc6e-9429-4539-a282-eadef235169e",
"attributes": {
"platform": "IOS",
"versionString": "5.9.0",
"appStoreState": "READY_FOR_SALE",
"copyright": "InterPro Solutions, LLC",
"releaseType": "MANUAL",
"earliestReleaseDate": null,
"usesIdfa": null,
"downloadable": true,
"createdDate": "2021-10-11T08:37:22-07:00"
},
"relationships": {
"ageRatingDeclaration": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/ageRatingDeclaration",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/ageRatingDeclaration"
}
},
"appStoreVersionLocalizations": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/appStoreVersionLocalizations",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/appStoreVersionLocalizations"
}
},
"build": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/build",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/build"
}
},
"appStoreVersionPhasedRelease": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/appStoreVersionPhasedRelease",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/appStoreVersionPhasedRelease"
}
},
"routingAppCoverage": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/routingAppCoverage",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/routingAppCoverage"
}
},
"appStoreReviewDetail": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/appStoreReviewDetail",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/appStoreReviewDetail"
}
},
"appStoreVersionSubmission": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/appStoreVersionSubmission",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/appStoreVersionSubmission"
}
},
"idfaDeclaration": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/idfaDeclaration",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/idfaDeclaration"
}
},
"appClipDefaultExperience": {
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/relationships/appClipDefaultExperience",
"related": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e/appClipDefaultExperience"
}
}
},
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/appStoreVersions/a75acc6e-9429-4539-a282-eadef235169e"
}
}
],
"links": {
"self": "https://api.appstoreconnect.apple.com/v1/apps/395389919/appStoreVersions?limit=1",
"next": "https://api.appstoreconnect.apple.com/v1/apps/395389919/appStoreVersions?cursor=AQ.ANZyDDk&limit=1"
},
"meta": {
"paging": {
"total": 68,
"limit": 1
}
}
}
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
App Store Connect
App Store Connect API
The new UISheetPresentationControllerDetents look great but only the medium size is new. Many applications would benefit from a small or extra small detent that only takes up 1/4th or 1/8th of the screen. Google maps is a good example.
Is there anyway to add custom detents or specify a specific sheet height?
I have a sheet thats being presented in SwiftUI and the first time it's opened it automatically dismisses itself half a second later. Reopening it from then on works properly. Has anyone else experienced this and perhaps come up with a solution?
Stack Overflow post: https://stackoverflow.com/questions/62722308/swiftui-sheet-automatically-dismisses-itself
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView:
NavigationView{
List{
ForEach(0..<10){ value in
Text("Hello, World \(value)")
}
}
NavigationLink(destination: Test()) {
Text("Details")
}
}
)
self.window = window
window.makeKeyAndVisible()
}
}
}
struct Test : View{
@State var show = false
var body : some View{
Text("Details")
.sheet(isPresented: $show, content: {
Color.blue
})
.toolbar{
ToolbarItem(placement: .navigationBarTrailing) {
Button("Show Sheet"){
show.toggle()
}
}
}
}
}