如何使用 UICollectionViewCompositionalLayout 为 iOS 设备创建相同的界面?

问题描述 投票:0回答:1

我希望我的界面在 iPhone 和 iPad 上看起来相同。就像我的图片一样:

enter image description here

我使用

UICollectionCompostionLayout
和这段代码来做到这一点:

func carouselSection(using section: Section) -> NSCollectionLayoutSection {
    
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
    let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
    
    var layoutGroupSize = NSCollectionLayoutSize(widthDimension: .absolute(0), heightDimension: .absolute(0))
    var layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize, subitems: [layoutItem])
    
    switch UIDevice.current.userInterfaceIdiom {
    case .phone:
        
        let a:CGFloat = UIScreen.main.bounds.size.height/8
        let b:CGFloat = UIScreen.main.bounds.size.height
        
        layoutGroupSize = NSCollectionLayoutSize(widthDimension: .absolute(b - (a) ), heightDimension: .absolute(b))
        layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize, subitems: [layoutItem])
        layoutGroup.contentInsets = NSDirectionalEdgeInsets(top: a, leading: a/2, bottom: a, trailing: a/2)
        
    case .pad:
        
        let a:CGFloat = UIScreen.main.bounds.size.height*0.25
        let h:CGFloat = a * 1.8
        let b:CGFloat = UIScreen.main.bounds.size.height
        
        layoutGroupSize = NSCollectionLayoutSize(widthDimension: .absolute(b - (h)), heightDimension: .absolute(b - (a)))
        layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize, subitems: [layoutItem])
        layoutGroup.contentInsets = NSDirectionalEdgeInsets(top: a, leading: a/10, bottom: 0, trailing: a/10)
        
    default:
        
        print(UIScreen.main.bounds.size.height)
    }

    let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
    layoutSection.orthogonalScrollingBehavior = .groupPagingCentered
    
    layoutSection.visibleItemsInvalidationHandler = { (items, offset, environment) in
        items.forEach { item in
            let distanceFromCenter = abs((item.frame.midX - offset.x) - environment.container.contentSize.width / 2.0)
            let minScale: CGFloat = 0.7
            let maxScale: CGFloat = 1.1
            let scale = max(maxScale - (distanceFromCenter / environment.container.contentSize.width), minScale)
            item.transform = CGAffineTransform(scaleX: scale, y: scale)
        }
    }
    
    return layoutSection
}

我得到的结果与我想要的大致相同。但我担心我的代码。我做了太多奇怪的计算,以使我的界面在 iPhone 和 iPad 上看起来相同。

对于 iPhone 来说是这样的:

let a:CGFloat = UIScreen.main.bounds.size.height/8
let b:CGFloat = UIScreen.main.bounds.size.height

在 iPad 上像这样:

let a:CGFloat = UIScreen.main.bounds.size.height*0.25
let h:CGFloat = a * 1.8
let b:CGFloat = UIScreen.main.bounds.size.height

我还为 iPhone 和 iPad 进行了不同的计算,尽管

UICollectionCompostionLayout
是专门为了进行最少的计算而创建的,但界面在不同设备上看起来是相同的。我应该在代码中修复什么?

ios swift
1个回答
0
投票

我想我得到了一个消除时髦计算的解决方案:

    func createLayout() -> UICollectionViewCompositionalLayout {
        UICollectionViewCompositionalLayout {
            (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)

            let interGroupSpacing = CGFloat(64)
            let width = layoutEnvironment.container.contentSize.width - interGroupSpacing * 2
            let groupWidth = width / 3
            
            let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(groupWidth), heightDimension: .absolute(groupWidth))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            
            let section = NSCollectionLayoutSection(group: group)
            let centerOffset = (layoutEnvironment.container.contentSize.height / 2) - (groupWidth / 2)
            section.contentInsets = NSDirectionalEdgeInsets(top: centerOffset, leading: 0, bottom: 0, trailing: 0)
            section.interGroupSpacing = interGroupSpacing * 1.5
            section.orthogonalScrollingBehavior = .groupPagingCentered
            section.contentInsetsReference = .none
            
            section.visibleItemsInvalidationHandler = { (items, offset, environment) in
                items.forEach { item in
                    let distanceFromCenter = abs((item.frame.midX - offset.x) - environment.container.contentSize.width / 2.0)
                    let minScale: CGFloat = 0.8
                    let maxScale: CGFloat = 1.1
                    let scale = max(maxScale - (distanceFromCenter / environment.container.contentSize.width), minScale)
                    item.transform = CGAffineTransform(scaleX: scale, y: scale)
                }
            }
            return section
        }
    }

我的主要想法是以

contentSize.width
为参考点,计算3个相同大小的盒子的
groupWidth

let interGroupSpacing = CGFloat(64)
let width = layoutEnvironment.container.contentSize.width - interGroupSpacing * 2
let groupWidth = width / 3

然后我们可以将组大小设置为此绝对值并计算部分偏移以使组垂直居中:

let centerOffset = (layoutEnvironment.container.contentSize.height / 2) - (groupWidth / 2)
section.contentInsets = NSDirectionalEdgeInsets(top: centerOffset, leading: 0, bottom: 0, trailing: 0)

最后一步是将

section.interGroupSpacing
设置为大于
interGroupSpacing
的值,例如
interGroupSpacing * 1.5
将左右组推出容器。

我还必须稍微调整你的缩放代码并添加

section.contentInsetsReference = .none
,因为 iPhone 上存在一些问题,元素出现在凹口后面。

iPhone 15 上的结果

Result on iPhone 15

iPad 10 代上的结果

Result on iPad 10th gen

© www.soinside.com 2019 - 2024. All rights reserved.