在多行中将项目包装在水平UIStackView中 [英] Wrap items in a horizontal UIStackView on multiple lines

查看:89
本文介绍了在多行中将项目包装在水平UIStackView中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用显示UITableView项的iOS应用. 每行将显示具有不同宽度的标签列表(由​​标签的文本长度决定). 我可以将所有标签放在水平的UIStackView中,但我希望它们绕多行而不是一个可滚动的行.基本上,我对类似于FlexBox的flex-wrap属性的功能感兴趣.

I am working on an iOS app which display a UITableView of items. Each row will show a list of tags with different widths(given by the tag's text length). I can place all the tags in a horizontal UIStackView but I want them to wrap on multiple lines instead of o a single scrollable one. Basically I'm interested in a functionality similar to FlexBox's flex-wrap property.

我已附上图片以供参考.

I've attached an image for reference.

有什么想法可以实现这一目标吗?

Any ideas how to achieve this?

推荐答案

有多种方法可以解决此问题.

There are a number of different ways to approach this.

一种方法-使用堆栈视图:

One approach - not using stack views:

  • 将标签添加到容器"视图
  • x = 0y = 0
  • 开头
  • 循环遍历标签,计算出新的x值(标签宽度+标签之间所需的间距)
  • 如果新的x将超出容器的边缘,请重置x = 0并在y上添加所需的高度以移至下一行"
  • 放置标签后,设置容器视图的高度
  • add your labels to a "container" view
  • start with x = 0 and y = 0
  • loop through the labels, calculating a new x value (label width + desired spacing between labels)
  • if the new x would be past the edge of the container, reset x = 0 and add desired height to y to "move to the next row"
  • after labels have been laid out, set the height of the container view

这是一个简单的例子:

class TagLabelsViewController: UIViewController {

    let containerView: UIView = {
        let v = UIView()
        return v
    }()

    let tagNames: [String] = [
        "First Tag",
        "Second",
        "Third Tag",
        "Fourth",
        "The Fifth Tag",
        "Sixth",
        "Seventh",
        "Tag Eight",
        "Here are some Letter Tags",
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
        "Nine",
        "Ten",
        "Eleven",
        "Tag Twelve",
        "Tag 13",
        "Fourteen",
        "Fifteen",
        "Sixteen",
        "Seventeen",
        "Eightteen",
        "Nineteen",
        "Last Tag",
    ]

    var tagLabels = [UILabel]()

    let tagHeight:CGFloat = 30
    let tagPadding: CGFloat = 16
    let tagSpacingX: CGFloat = 8
    let tagSpacingY: CGFloat = 8

    // container view height will be modified when laying out subviews
    var containerHeightConstraint: NSLayoutConstraint = NSLayoutConstraint()

    override func viewDidLoad() {
        super.viewDidLoad()

        // add the container view
        view.addSubview(containerView)

        // give it a background color so we can see it
        containerView.backgroundColor = .yellow

        // use autolayout
        containerView.translatesAutoresizingMaskIntoConstraints = false

        // initialize height constraint - actual height will be set later
        containerHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: 10.0)

        // constrain container safe-area top / leading / trailing to view with 20-pts padding
        let g = view.safeAreaLayoutGuide

        NSLayoutConstraint.activate([
            containerView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            containerView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            containerView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            containerHeightConstraint,
        ])

        // add the buttons to the scroll view
        addTagLabels()

    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // call this here, after views have been laid-out
        // this will also be called when the size changes, such as device rotation,
        // so the buttons will "re-layout"
        displayTagLabels()

    }

    func addTagLabels() -> Void {

        for j in 0..<self.tagNames.count {

            // create a new label
            let newLabel = UILabel()

            // set its properties (title, colors, corners, etc)
            newLabel.text = tagNames[j]
            newLabel.textAlignment = .center
            newLabel.backgroundColor = UIColor.cyan
            newLabel.layer.masksToBounds = true
            newLabel.layer.cornerRadius = 8
            newLabel.layer.borderColor = UIColor.red.cgColor
            newLabel.layer.borderWidth = 1

            // set its frame width and height
            newLabel.frame.size.width = newLabel.intrinsicContentSize.width + tagPadding
            newLabel.frame.size.height = tagHeight

            // add it to the scroll view
            containerView.addSubview(newLabel)

            // append it to tagLabels array
            tagLabels.append(newLabel)

        }

    }

    func displayTagLabels() {

        let containerWidth = containerView.frame.size.width

        var currentOriginX: CGFloat = 0
        var currentOriginY: CGFloat = 0

        // for each label in the array
        tagLabels.forEach { label in

            // if current X + label width will be greater than container view width
            //  "move to next row"
            if currentOriginX + label.frame.width > containerWidth {
                currentOriginX = 0
                currentOriginY += tagHeight + tagSpacingY
            }

            // set the btn frame origin
            label.frame.origin.x = currentOriginX
            label.frame.origin.y = currentOriginY

            // increment current X by btn width + spacing
            currentOriginX += label.frame.width + tagSpacingX

        }

        // update container view height
        containerHeightConstraint.constant = currentOriginY + tagHeight

    }

}

结果:

这非常简单,并且代码中的注释使您能够适应您的需求.

It's pretty straight-forward, and with the comments in the code you should be able to adapt it to your needs.

如果您想要一个预构建"的解决方案(可能具有更多功能),请搜索

If you want a "pre-built" solution, perhaps with more features, searching for

swift left aligned tags view

出现很多匹配项.这个(我与此无关)看起来很有趣: https://github.com/ElaWorkshop/TagListView

comes up with lots of matches. This one (I have nothing to do with it) looks interesting: https://github.com/ElaWorkshop/TagListView

这篇关于在多行中将项目包装在水平UIStackView中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆