首页 > 解决方案 > 如何根据屏幕宽度动态设置具有不同字符串长度的多个按钮?

问题描述

例子

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

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


遵循@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 的代码完全相同。但是,我仍然无法得到我想要实现的东西。

在此处输入图像描述

我没能做出我想要的。

标签: iosswiftbuttonlayout

解决方案


要有效地做到这一点,您需要一个UICollectionView带有自定义的FlowLayout. 我要做一个storyboard例子。这很复杂,所以我会尽力而为。所有代码都将在步骤下方。

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

第 2 步:添加UICollectionView到您的ViewController

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

图片1

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

UICollectionViewCell

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

第 7 步:将 ViewController 代码添加到您的 ViewController 类。此代码允许您将单元格添加到集合视图中。sizeForItemAt 函数将允许您根据放置在每个单元格内的字符串的宽度调整单元格的大小。

代码:

视图控制器:

    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
            }
        }
    }
}

推荐阅读