微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

N个“收藏夹视图”单元格-自动调整大小以触发屏幕中的所有单元格

如何解决N个“收藏夹视图”单元格-自动调整大小以触发屏幕中的所有单元格

我需要始终将收藏视图单元格设置在iphone屏幕范围内。

它应该像:

  • 如果是一个单元格,则应填满整个屏幕
  • 如果有两个单元格,则第一个单元格应填充前半部分,第二个单元格应填充后半部分
  • 如果有三个单元格,则屏幕应划分为四个相等的单元格,第四个单元格的占位符应为​​空。如果是第四个单元格,则应填充空白区域。
  • 如果是五个/六个单元格,则应该有三行,每行两个单元格。

我有一个逻辑,但由于受到一些黑客的攻击,我设法仅支持6个单元,此后它不起作用。

func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeforItemAt indexPath: IndexPath) -> CGSize {
        
        var horizontalTiles = 1
        var verticalTiles = 1
        
        var targetWidth = collectionView.frame.width
        var targetHeight = collectionView.frame.height - UIApplication.shared.statusBarFrame.height
        
        horizontalTiles = horizontalTiles+(self.contactsArray.count/3)
        verticalTiles = verticalTiles+(self.contactsArray.count/2)
        
        if self.contactsArray.count%4 == 0 || self.contactsArray.count%6 == 0 {
            return lastCellSize
        }
        
        targetWidth = targetWidth / CGFloat(horizontalTiles)
        targetHeight = targetHeight / CGFloat(verticalTiles)
        
        let size = CGSize(width: targetWidth,height: targetHeight)
        
        lastCellSize = size
        
        return size
    }

如果有更好的方法或使用流布局,那将非常有帮助。

enter image description here

解决方法

将动画放在一边...您可以通过一些聪明的数学/逻辑来获得尺寸(您的问题专门询问尺寸问题)。

一些观察/假设:

  • 所有单元格的大小相同,因此我们可以返回一个大小
  • 行/列交替增加的数量
  • 行在列之前递增
  • 在所有列都填入最后一行之前,大小保持不变

给出这个...

func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAt indexPath: IndexPath) -> CGSize {

    let numItems = self.contactsArray.count

    let targetWidth = collectionView.frame.width
    let targetHeight = collectionView.frame.height - UIApplication.shared.statusBarFrame.height

    if numItems == 1 {
        return CGSize(width: targetWidth,height: targetHeight)
    }
    
    // Below logic only works for numItems > 1,so we check for that ^

    var numRows = 1
    var numColumns = 1

    for index in 1...(numItems-1) {
        if index % numColumns == 0 {
            if numColumns == numRows {
                numRows += 1
            } else {
                numColumns += 1
            }
        }
    }

    return CGSize(width: targetWidth / numColumns,height: targetHeight / numRows)
}
,

如果您不希望使用集合视图,这是另一种方法。

考虑行和列。行数将是总计项的平方根的上限,列数将是总计项的上限除以行数。

然后,您可以轻松计算出“平铺”尺寸。

enter image description here

示例代码:

class ArrangeViewController: UIViewController {
    
    // Add a view button
    let addButton: UIButton = {
        let v = UIButton()
        v.setTitle("Add",for: .normal)
        return v
    }()
    
    // Remove a view button
    let remButton: UIButton = {
        let v = UIButton()
        v.setTitle("Remove",for: [])
        return v
    }()
    
    // horizontal stackview to hold the buttons
    let btnsStack: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .horizontal
        v.alignment = .fill
        v.distribution = .fillEqually
        v.spacing = 20
        return v
    }()
    
    // view to hold the added views
    let tilesContainerView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .systemRed
        v.clipsToBounds = true
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBlue
        
        // button properties
        [addButton,remButton].forEach { b in
            b.backgroundColor = .yellow
            b.setTitleColor(.blue,for: .normal)
            b.setTitleColor(.lightGray,for: .highlighted)
        }
        
        // add the buttons to the stack view
        btnsStack.addArrangedSubview(addButton)
        btnsStack.addArrangedSubview(remButton)
        
        // add buttons stack to the view
        view.addSubview(btnsStack)
        
        // add border container to the view
        view.addSubview(tilesContainerView)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain buttons stack Top / Leading / Trailing with a little "padding"
            btnsStack.topAnchor.constraint(equalTo: g.topAnchor,constant: 12.0),btnsStack.leadingAnchor.constraint(equalTo: g.leadingAnchor,constant: 20.0),btnsStack.trailingAnchor.constraint(equalTo: g.trailingAnchor,constant: -20.0),// buttons height to 40-pts (just for asthetics)
            btnsStack.heightAnchor.constraint(equalToConstant: 40.0),// constrain border container
            // 20-pts below buttons
            tilesContainerView.topAnchor.constraint(equalTo: btnsStack.bottomAnchor,// 20-pts from view bottom
            tilesContainerView.bottomAnchor.constraint(equalTo: g.bottomAnchor,// 20-pts Leading and Trailing
            tilesContainerView.leadingAnchor.constraint(equalTo: g.leadingAnchor,tilesContainerView.trailingAnchor.constraint(equalTo: g.trailingAnchor,])
        
        // add actions for the Add and Delete buttons
        addButton.addTarget(self,action: #selector(addTapped(_:)),for: .touchUpInside)
        remButton.addTarget(self,action: #selector(remTapped(_:)),for: .touchUpInside)
        
    }
    
    override func viewWillTransition(to size: CGSize,with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size,with: coordinator)
        
        coordinator.animate(alongsideTransition: { _ in
        }) { [unowned self] _ in
            self.arrangeViews()
        }
        
    }
    
    @objc func addTapped(_ sender: Any?) -> Void {
        
        // instantiate a new custom view and add it to
        // the inner container view
        let v = MyArrangeView()
        tilesContainerView.addSubview(v)
        v.theLabel.text = "\(tilesContainerView.subviews.count)"
        
        // update the arrangement
        arrangeViews()
        
    }
    
    @objc func remTapped(_ sender: Any?) -> Void {
        
        // if inner container has at least one custom view
        if let v = tilesContainerView.subviews.last {
            
            // remove it
            v.removeFromSuperview()
            
            // update the arrangement
            arrangeViews()
            
        }
        
    }
    
    func arrangeViews() -> Void {
        
        // make sure there is at least 1 subview to arrange
        guard tilesContainerView.subviews.count > 0 else { return }
        
        // init local vars to use
        // Note: making them all CGFLoats makes it easier to use in expressions - avoids a lot of casting CGFloat(var)
        
        var numCols: CGFloat = 0
        var numRows: CGFloat = 0
        
        var w: CGFloat = 0
        var h: CGFloat = 0
        
        // this is the frame we need to fit inside
        let containerWidth: CGFloat = tilesContainerView.frame.size.width
        let containerHeight: CGFloat = tilesContainerView.frame.size.height
        
        // number of views to arrange
        let numTiles: CGFloat = CGFloat(tilesContainerView.subviews.count)
        
        // get the ceil of the square root of number of tiles
        //  that's the number of rows
        numRows = CGFloat(ceil(sqrt(numTiles)))
        
        // get the ceil of the number of tiles divided by number of rows
        //  that's the number of columns
        numCols = CGFloat(ceil(numTiles / numRows))

        // size of each tile
        w = containerWidth / numCols
        h = containerHeight / numRows
        
        var x: CGFloat = 0.0
        var y: CGFloat = 0.0
        
        UIView.animate(withDuration: 0.3,animations: {
            
            // loop through,doing the actual layout (setting each item's frame)
            self.tilesContainerView.subviews.forEach { v in
                
                v.frame = CGRect(x: x,y: y,width: w,height: h)
                x += w
                if x + w > containerWidth + 1 {
                    x = 0.0
                    y += h
                }
                
            }
            
            self.view.layoutIfNeeded()
        })

    }
    
}


// simple bordered custom view with a label in a "content container"
class MyArrangeView: UIView {
    
    // this will hold the "content" of the custom view
    // for this example,it just holds a label
    let theContentView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .systemTeal
        return v
    }()
    
    let theLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .clear
        v.textAlignment = .center
        v.font = UIFont.systemFont(ofSize: 14.0)
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() -> Void {
        self.backgroundColor = .systemYellow
        
        // add the label to the content view
        theContentView.addSubview(theLabel)
        
        // add the content view to self
        addSubview(theContentView)
        
        NSLayoutConstraint.activate([
            
            // constrain the label to all 4 sides of the content view
            theLabel.topAnchor.constraint(equalTo: theContentView.topAnchor,constant: 0.0),theLabel.bottomAnchor.constraint(equalTo: theContentView.bottomAnchor,theLabel.leadingAnchor.constraint(equalTo: theContentView.leadingAnchor,theLabel.trailingAnchor.constraint(equalTo: theContentView.trailingAnchor,// constrain the content view to all 4 sides of self with 5-pts "padding"
            theContentView.topAnchor.constraint(equalTo: topAnchor,constant: 5.0),theContentView.bottomAnchor.constraint(equalTo: bottomAnchor,constant: -5.0),theContentView.leadingAnchor.constraint(equalTo: leadingAnchor,theContentView.trailingAnchor.constraint(equalTo: trailingAnchor,])
        
        layer.borderWidth = 1
        layer.borderColor = UIColor.systemGray.cgColor
    }
    
}

然后旋转...

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。