ios - 如何根据屏幕宽度动态设置具有不同字符串长度的多个按钮?

标签 ios swift button layout

example
(来源:uimovement.com)

我想像上面那样实现布局(当屏幕的宽度不足以容纳按钮的宽度时自动换行)。 但我无法想出如何制作像布局一样的图像。我只能静态实现,不能动态实现。

在Android中,有一个layout可以实现上面的。 但是我不知道有什么可以帮助我快速实现上面的图像。 请帮助我。


遵循@Matthew Mitchell 的建议。 我像下面这样实现它。

我的 ViewController.swift

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    var hobbyArray = [String]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self
//        self.collectionView!.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        
        hobbyArray.append("test1")
        hobbyArray.append("test2")
        hobbyArray.append("test3")
        hobbyArray.append("test4")
        hobbyArray.append("test5")
        hobbyArray.append("test5")
        hobbyArray.append("test5123123")
        
        collectionView.reloadData()
    }
}

extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return hobbyArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
        
        cell.title.text = self.hobbyArray[indexPath.row]
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        let text = self.hobbyArray[indexPath.row]
        let cellWidth = text.size(withAttributes:[.font: UIFont.systemFont(ofSize:17)]).width + 25
        return CGSize(width: cellWidth, height: 35.0)
    }
}

其他代码的实现与@Matthew Mitchell 的代码完全相同。 但是,我仍然无法实现我想要实现的。

enter image description here

我没能做出我想要的。

最佳答案

要高效地执行此操作,您需要有一个带有自定义 FlowLayoutUICollectionView。我将做一个 storyboard 示例。这很复杂,所以我会尽力而为。所有代码都在步骤下方。

第 1 步:创建一个名为 CollectionViewFlowLayout 的 swift 文件,并在新创建的类中使用 UICollectionViewLayout 代码。

第 2 步:将 UICollectionView 添加到您的 ViewController

第 3 步:将新的 UICollectionView 布局与 CollectionViewFlowLayout 类链接

Picture 1

第 4 步:在 UICollectionView 内部创建一个 UICollectionViewCell,向该单元格添加标签并将其约束在单元格中的左右并使其垂直居中。在单元格的属性检查器中,给它一个可重用的标识符(本例中为“单元格”)

UICollectionViewCell

第 6 步:创建一个名为 collectionViewCell 的 swift 文件,并使用链接到您的 collectionViewCell 的 UICollectionViewCell 类(与您在第 3 步中链接流程布局的方式相同)。

第 7 步:将 ViewController 代码添加到您的 ViewController 类。此代码允许您将单元格添加到您的 Collection View 。 sizeForItemAt 函数允许您根据放入每个单元格中的字符串的宽度调整单元格的大小。

代码:

View Controller :

    import UIKit


        class viewController: UIViewController {

            //Outlets
            @IBOutlet weak var collectionView: UICollectionView!

            override func viewDidLoad() {
                collectionView.delegate = self
                collectionView.dataSource = self
            }
        }

        extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
            func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                return YOUR_ITEM_COUNT
            }

            func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell

                self.title.text = YOUR_ITEMS_LIST[indexPath.row]
                return cell
            }

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

            let text = YOUR_ITEMS_LIST[indexPath.row]
            let cellWidth = text!.size(withAttributes:[.font: UIFont.systemFont(ofSize:17)]).width + 25
            return CGSize(width: cellWidth, height: 35.0)
        }
    }

UICollectionViewCell:

class CollectionViewCell: UICollectionViewCell {

   //Outlets
    @IBOutlet weak var title: UILabel!
}

UICollectionViewFlowLayout:

import UIKit

class CollectionViewFlowLayout: UICollectionViewFlowLayout {
    var tempCellAttributesArray = [UICollectionViewLayoutAttributes]()
    let leftEdgeInset: CGFloat = 0

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let cellAttributesArray = super.layoutAttributesForElements(in: rect)
        //Oth position cellAttr is InConvience Emoji Cell, from 1st onwards info cells are there, thats why we start count from 2nd position.
        if(cellAttributesArray != nil && cellAttributesArray!.count > 1) {
            for i in 1..<(cellAttributesArray!.count) {
                let prevLayoutAttributes: UICollectionViewLayoutAttributes = cellAttributesArray![i - 1]
                let currentLayoutAttributes: UICollectionViewLayoutAttributes = cellAttributesArray![i]
                let maximumSpacing: CGFloat = 8
                let prevCellMaxX: CGFloat = prevLayoutAttributes.frame.maxX
                //UIEdgeInset 30 from left
                let collectionViewSectionWidth = self.collectionViewContentSize.width - leftEdgeInset
                let currentCellExpectedMaxX = prevCellMaxX + maximumSpacing + (currentLayoutAttributes.frame.size.width )
                if currentCellExpectedMaxX < collectionViewSectionWidth {
                    var frame: CGRect? = currentLayoutAttributes.frame
                    frame?.origin.x = prevCellMaxX + maximumSpacing
                    frame?.origin.y = prevLayoutAttributes.frame.origin.y
                    currentLayoutAttributes.frame = frame ?? CGRect.zero
                } else {
                    // self.shiftCellsToCenter()
                    currentLayoutAttributes.frame.origin.x = leftEdgeInset
                    //To Avoid InConvience Emoji Cell
                    if (prevLayoutAttributes.frame.origin.x != 0) {
                        currentLayoutAttributes.frame.origin.y = prevLayoutAttributes.frame.origin.y + prevLayoutAttributes.frame.size.height + 08
                    }
                }
            }
        }

        return cellAttributesArray
    }

    func shiftCellsToCenter() {
        if (tempCellAttributesArray.count == 0) {return}
        let lastCellLayoutAttributes = self.tempCellAttributesArray[self.tempCellAttributesArray.count-1]
        let lastCellMaxX: CGFloat = lastCellLayoutAttributes.frame.maxX
        let collectionViewSectionWidth = self.collectionViewContentSize.width - leftEdgeInset
        let xAxisDifference = collectionViewSectionWidth - lastCellMaxX
        if xAxisDifference > 0 {
            for each in self.tempCellAttributesArray{
                each.frame.origin.x += xAxisDifference/2
            }
        }
    }
}

关于ios - 如何根据屏幕宽度动态设置具有不同字符串长度的多个按钮?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57832328/

相关文章:

javascript - 尝试将 onclick() 函数附加到按钮时有哪些解决问题的技巧?

css - 它是如何完成的 - Tweet-Button 计数器的缩放

java - 删除 JavaFX 按钮填充?

ios - 在dealloc方法中检查保留计数

ios - 我的 native 应用程序在Swift中编译器生成的崩溃

ios - 使用 AutoLayout 以编程方式创建 UICollectionView

ios - 当我按下按钮推送到另一个 ViewController 时,我怎么知道我的按钮在哪个 indexPath.row 中?

iOS 将压缩的 NSData 写入文件会生成损坏的 zip 文件

ios - 如何在iOS设备上的Chrome移动版上进行远程调试

ios - 如何在 Swift 中关闭 Controller View 时传输数据