ios - 苹果自定义布局算法如何保持纵横比?
问题描述
我正在尝试创建一个自定义布局,如下所示。目前,我的单元格正在通过硬编码它们的尺寸并将单元格内部设置contentmode
为和来调整大小。图像显示为缩放。如下所示,如何实现在不同单元格尺寸下保持纵横比的布局。在下面的布局中,高度和宽度似乎是前缀。 UIImageView
.scaleAspectFill
clipsToBounds = true
[ ] 1 [ ]
我对自定义布局代码的尝试
import UIKit
class gridLayouts{
static var screenHeight = UIScreen.main.bounds.height
static var screenWidth = UIScreen.main.bounds.width
var xOffsets:[CGFloat]
var yOffsets:[CGFloat]
var itemWidths:[CGFloat]
var itemHeights:[CGFloat]
var blockHeight:CGFloat?
init(xOffsets:[CGFloat],yOffsets:[CGFloat],itemWidths:[CGFloat], itemHeights:[CGFloat],blockHeight:CGFloat) {
self.xOffsets = xOffsets
self.yOffsets = yOffsets
self.itemWidths = itemWidths
self.itemHeights = itemHeights
self.blockHeight = blockHeight
}
func calcBlockHeight()->CGFloat{
var blockHeight:CGFloat = 0
for item in 0...itemWidths.count-1{
if self.xOffsets[item] + self.itemWidths[item] ==
UIScreen.main.bounds.width{ ((self.itemWidths[item]+xOffsets[item])/UIScreen.main.bounds.width)")
blockHeight += self.itemHeights[item]
}
}
return blockHeight
}
func updateYoffSets(previousBlockHeight:CGFloat)->[CGFloat]{
var updatedYoffsets = self.yOffsets
for item in 0...self.yOffsets.count - 1{
updatedYoffsets[item] += previousBlockHeight
}
return updatedYoffsets
}
}
class customCollectionViewLayout:UICollectionViewLayout{
// 2
fileprivate var numberOfColumns = 2
fileprivate var cellPadding: CGFloat = 0
// 3
fileprivate var cache = [UICollectionViewLayoutAttributes]()
// 4
fileprivate var contentHeight: CGFloat = 0
fileprivate var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
// 5
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
// 1
guard cache.isEmpty == true, let collectionView = collectionView else {
return
}
setUpLayout()
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
// 3
var totalBlockHeight:CGFloat = 0
var currentgridLayout:gridLayouts = appleLayout
var updatedYoffSets:[CGFloat] = [CGFloat]()
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
if item%8 == 0{
print("\(item): Im divisible by 8")
if (collectionView.numberOfItems(inSection: 0) - item < 8){
print("Im inside the if \(item)")
switch (collectionView.numberOfItems(inSection: 0) - item )%8{
case 0:
print("Im in case 0")
currentgridLayout = NextLayout()
case 1:
print("Im in case 1")
currentgridLayout = gridLayouts(xOffsets: [0], yOffsets: [0], itemWidths: [screenWidth], itemHeights: [screenHeight/3], blockHeight: screenHeight/3)
case 2:
print("Im in case 2")
currentgridLayout = gridLayouts(xOffsets: [0,screenWidth/2], yOffsets: [0,0], itemWidths: [screenWidth/2,screenWidth/2], itemHeights: [screenHeight/3], blockHeight: screenHeight/3)
case 3:
print("Im in case 3")
currentgridLayout = gridLayouts(xOffsets: [0,screenWidth/3,2*screenWidth/3], yOffsets: [0,0,0], itemWidths: [screenWidth/3,screenWidth/3,screenWidth/3], itemHeights: [screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: screenHeight/3)
case 4:
print("Im in case 4")
currentgridLayout = gridLayouts(xOffsets: [0,2*screenWidth/3,0,screenWidth/3], yOffsets: [0,0,screenHeight/3,screenHeight/3], itemWidths: [2*screenWidth/3,screenWidth/3,screenWidth/3,2*screenWidth/3], itemHeights: [screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: 2*screenHeight/3)
case 5:
print("Im in case 5")
currentgridLayout = gridLayouts(xOffsets: Array(appleLayout.xOffsets.prefix(through: 4)), yOffsets: Array(appleLayout.yOffsets.prefix(through: 4)), itemWidths: Array(appleLayout.itemWidths.prefix(through: 4)), itemHeights: Array(appleLayout.itemHeights.prefix(through: 4)), blockHeight: appleLayout.blockHeight!)
print("currentgridLayout.xOffsets.count: \(currentgridLayout.xOffsets.count)")
case 6:
print("Im in case 6")
currentgridLayout = gridLayouts(xOffsets: [0,2*screenWidth/3,2*screenWidth/3,0,screenWidth/3,2*screenWidth/3], yOffsets: [0,0,0,2*screenHeight/3,2*screenHeight/3,2*screenHeight/3], itemWidths: [2*screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3], itemHeights: [2*screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: screenHeight)
case 7:
print("Im in case 7")
currentgridLayout = gridLayouts(xOffsets: [0,2*screenWidth/3,2*screenWidth/3,0,screenWidth/3,2*screenWidth/3,0], yOffsets: [0,0,0,2*screenHeight/3,2*screenHeight/3,2*screenHeight/3,screenHeight], itemWidths: [2*screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth], itemHeights: [2*screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,2*screenHeight/3], blockHeight: screenHeight+2*screenHeight/3)
default:
print("Im in the default case")
currentgridLayout = NextLayout()
}
}
updatedYoffSets = currentgridLayout.updateYoffSets(previousBlockHeight: totalBlockHeight)
totalBlockHeight += currentgridLayout.calcBlockHeight()
}
let frame = CGRect(x: currentgridLayout.xOffsets[item%8], y: updatedYoffSets[item%8], width: currentgridLayout.itemWidths[item%8], height: currentgridLayout.itemHeights[item%8])
//
var insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
//changed
insetFrame = frame.insetBy(dx: 2, dy: 2)
// 5
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
// 6
contentHeight = max(contentHeight, frame.maxY)
//yOffset[column] = yOffset[column] + blockHeight
//push the y insets down
}
print("The block height is \(currentgridLayout.calcBlockHeight())")
print("The block height is \(currentgridLayout.calcBlockHeight()/UIScreen.main.bounds.height) screens")
}
func NextYOffSet( yOffset:[CGFloat],previousBlockHeight:CGFloat)->[CGFloat]{
var offSet = yOffset
for item in 0...offSet.count{
offSet[item] += previousBlockHeight
}
return offSet
}
func NextLayout()->gridLayouts{
let rand = Int(arc4random_uniform(UInt32(2)))
print("rand num \(rand)")
switch rand {
case 0:
print("Apple Layout Returned")
return appleLayout
default:
print("My Layout Returned")
return myLayout
}
}
var myLayout:gridLayouts!
var appleLayout:gridLayouts!
func setUpLayout(){
let screenWidth = gridLayouts.screenWidth
let screenHeight = gridLayouts.screenHeight
myLayout = gridLayouts(
xOffsets: [0,screenWidth/4,screenWidth/2,0,screenWidth/4,0,screenWidth/2,0],
yOffsets: [0,0,0,screenHeight/4,screenHeight/4,screenHeight/2,screenHeight/2,screenHeight],
itemWidths: [screenWidth/4,screenWidth/4,screenWidth/2,screenWidth/4,screenWidth/4,screenWidth/2,screenWidth/2,screenWidth],
itemHeights: [screenHeight/4,screenHeight/4,screenHeight/2,screenHeight/4,screenHeight/4,screenHeight/2,screenHeight/2,screenHeight],
blockHeight: 2*screenHeight)
appleLayout = gridLayouts(xOffsets: [0,screenWidth/3,0,screenWidth/3,2*screenWidth/3,0,2*screenWidth/3,2*screenWidth/3], yOffsets: [0,0,screenHeight/3,screenHeight/3,screenHeight/3,2*screenHeight/3,2*screenHeight/3,screenHeight], itemWidths: [screenWidth/3,2*screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,2*screenWidth/3,screenWidth/3,screenWidth/3], itemHeights: [screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,2*screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: 4*screenHeight/3)
print("myLayout blockHeight = \(myLayout.calcBlockHeight()/screenHeight)")
print("appleLayout blockHeight = \(appleLayout.calcBlockHeight()/screenHeight)")
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
extension Array where Iterator.Element == CGFloat{
mutating func incrementBy(_ amount:CGFloat){
for element in 0...self.count-1{
self[element] += amount
}
}
func incrementedArray(_ amount:CGFloat)->[CGFloat]{
var incrementedArray = self
for element in 0...incrementedArray.count-1{
incrementedArray[element] += amount
}
return incrementedArray
}
}
解决方案
推荐阅读
- node.js - 如何使用服务帐户凭据初始化 Google Cloud Storage NodeJS 客户端库
- apache-kafka - Confluent Replicator 无法重新配置连接器任务?
- r - 为什么在 R 3.5.0 中运行 ggplot2 时出现错误?
- python - ValueError:无法解码 JSON 对象 - Python 2.7 脚本
- php - 识别一个词并提取对应的数据
- python - PySpark Dataframe 中的 SMOTE 重采样
- networking - 如果您在浏览器上打开网站然后连接到 vpn,这些网站会发送到 vpn 提供商吗?
- php - 将 PHP 数组结果打印到 HTML 可选列表中
- excel - EXACT 函数在数组公式中返回“#N/A”错误?
- c# - 使用 costura 嵌入报表查看器 dll 时出错