将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

huangapple go评论62阅读模式
英文:

Add views to UIStackView and have them shrink in width of the screen width runs out

问题

我在Storyboard中有一个UIStackView,像这样:

@IBOutlet weak var stackView: UIStackView!

我想要能够以编程方式向这个UIStackView添加视图,就像这样:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
view.backgroundColor = .gray        
stackView.addArrangedSubview(view)

最初添加的视图将是50x50的尺寸。当只添加了少数视图时,我希望它们保持50x50的尺寸并居中在屏幕上。

但是,当添加的视图数量超过屏幕的宽度时,我希望它们会缩小尺寸。

这是我想要的效果。第一行是添加了三个50x50的视图。接下来的行添加了更多的视图,请注意它们如何缩小以适应屏幕的宽度:

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

通过UIStackView以这种方式以编程方式添加视图是否可能?

英文:

I have a UIStackView in storyboard like this:

@IBOutlet weak var stackView: UIStackView!

I want to be able to add views to this UIStackView programmatically like this:

    let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
    view.backgroundColor = .gray        
    stackView.addArrangedSubview(view)

Initially, the views added will be 50x50 in dimensions. When only a few are added, I want them to stay 50x50 and be centered in the screen.

But when you add more than there is width on the screen, I want them to shrink in size.

Here is what I want it to look like. The first row is with three 50x50 views added. The next row has more added and notice how they shrink in width to fit the width of the screen:

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

Is this possible with a UIStackView and adding views programmatically like this?

答案1

得分: 3

以下是翻译好的内容:

这可以只使用自动布局约束来完成,不需要“计算”大小。

从一个堆栈视图开始:

  • UIStackView
    • 水平轴
    • 根据需要设置间距
    • Distribution: Fill Equally
  • 将高度约束设置为 50
  • 将 centerX 约束设置为视图的中心X
  • 将前导约束设置为 大于等于 视图前导边界加 8 个点("侧边填充")
  • 将尾随约束设置为 小于等于 视图尾随边界减 8 个点("侧边填充")

每次添加一个已排列的子视图时,都要给它一个 宽度 约束,设置为 50,但优先级设置为 .defaultHigh

这告诉自动布局:“尝试使视图的宽度为 50 个点。如果不能*,然后使用下一个自动布局命令来设置其宽度。”在这种情况下,“下一个”命令将是堆栈视图的 Fill Equally 属性。

这是一些快速示例代码。在顶部附近有一个堆栈视图,从一个子视图开始... 还有“添加”和“移除”按钮:

class ViewController: UIViewController {
    
    let stackView = UIStackView()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // 堆栈视图属性
        stackView.axis = .horizontal
        stackView.distribution = .fillEqually
        stackView.spacing = 6

        stackView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stackView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            
            // 我们希望高度始终为 50 个点
            stackView.heightAnchor.constraint(equalToConstant: 50.0),
            
            // 保持堆栈视图的左右端至少距离边界 8 个点
            stackView.leadingAnchor.constraint(greaterThanOrEqualTo: g.leadingAnchor, constant: 8.0),
            stackView.trailingAnchor.constraint(lessThanOrEqualTo: g.trailingAnchor, constant: -8.0),

            // 水平居中
            stackView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            
        ])
        
        // “添加”和“移除”按钮
        var cfg = UIButton.Configuration.filled()
        
        cfg.title = "添加"
        
        let addBtn = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
            self.addView()
        })
        
        cfg.title = "移除"
        
        let remBtn = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
            self.removeView()
        })
        
        addBtn.translatesAutoresizingMaskIntoConstraints = false
        remBtn.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(addBtn)
        view.addSubview(remBtn)
        
        NSLayoutConstraint.activate([
            
            addBtn.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 20.0),
            addBtn.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            
            remBtn.leadingAnchor.constraint(equalTo: addBtn.trailingAnchor, constant: 20.0),

            remBtn.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 20.0),
            remBtn.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),

            remBtn.widthAnchor.constraint(equalTo: addBtn.widthAnchor),
            
        ])
        
        // 从一个已排列的子视图开始
        addView()
        
    }
    
    func addView() {
        let v = UIView()
        v.backgroundColor = .lightGray
        // 告诉自动布局尝试使已排列的子视图的宽度为 50 个点
        // 但允许它“破坏”
        let w: NSLayoutConstraint = v.widthAnchor.constraint(equalToConstant: 50.0)
        w.priority = .defaultHigh
        w.isActive = true
        stackView.addArrangedSubview(v)
    }
    
    func removeView() {
        // 至少保留一个已排列的子视图
        if stackView.arrangedSubviews.count > 1 {
            stackView.arrangedSubviews.last?.removeFromSuperview()
        }
    }
    
}

看起来像这样:

英文:

This can be done with auto layout constraints only... no need to "calculate" sizing.

Start with a stack view:

  • UIStackView
    • horizontal axis
    • spacing as desired
    • Distribution: Fill Equally
  • constrain the Height to 50
  • constrain centerX to view centerX
  • constrain Leading greaterThanOrEqualTo view leading plus 8-points ("side padding")
  • constrain Trailing lessThanOrEqualTo view trailing minus 8-points ("side padding")

Every time you add an arranged subview, give it a Width constraint of 50 -- but with a Priority of .defaultHigh.

That tells auto layout: "TRY to make the view 50-points wide. If you can't, then use the next auto layout command for its width." In this case, the "next" command will be the stack view's Fill Equally property.

Here's some quick example code. A stack view near the top, starting with one subview... along with "Add" and "Remove" buttons:

class ViewController: UIViewController {
let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
// stack view properties
stackView.axis = .horizontal
stackView.distribution = .fillEqually
stackView.spacing = 6
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
// we want height always at 50-points
stackView.heightAnchor.constraint(equalToConstant: 50.0),
// keep left and right ends of stack view AT LEAST 8-points from the sides
stackView.leadingAnchor.constraint(greaterThanOrEqualTo: g.leadingAnchor, constant: 8.0),
stackView.trailingAnchor.constraint(lessThanOrEqualTo: g.trailingAnchor, constant: -8.0),
// centered horizontally
stackView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
])
// "Add" and "Remove" buttons
var cfg = UIButton.Configuration.filled()
cfg.title = "Add"
let addBtn = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
self.addView()
})
cfg.title = "Remove"
let remBtn = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
self.removeView()
})
addBtn.translatesAutoresizingMaskIntoConstraints = false
remBtn.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(addBtn)
view.addSubview(remBtn)
NSLayoutConstraint.activate([
addBtn.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 20.0),
addBtn.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
remBtn.leadingAnchor.constraint(equalTo: addBtn.trailingAnchor, constant: 20.0),
remBtn.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 20.0),
remBtn.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
remBtn.widthAnchor.constraint(equalTo: addBtn.widthAnchor),
])
// start with one arranged subview
addView()
}
func addView() {
let v = UIView()
v.backgroundColor = .lightGray
// tell autolayout to TRY to make the arranged subview 50-points width
//	but allow it to "break"
let w: NSLayoutConstraint = v.widthAnchor.constraint(equalToConstant: 50.0)
w.priority = .defaultHigh
w.isActive = true
stackView.addArrangedSubview(v)
}
func removeView() {
// keep at least one arranged subview
if stackView.arrangedSubviews.count > 1 {
stackView.arrangedSubviews.last?.removeFromSuperview()
}
}
}

Looks like this:

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

答案2

得分: 1

是的,这是可能的。
您可以设置以下内容:

约束条件:

  1. 添加您想要的一些高度约束。
  2. 为堆栈视图添加最小宽度。
  3. 为堆栈视图添加X和Y位置。

堆栈视图属性:

  1. 将对齐方式设置为填充。
  2. 将分布设置为均匀填充。
  3. 添加一些间距,我已经添加了5。

代码:

  1. 在UIViewController类中获取堆栈视图宽度的IBOutlet。
  2. 计算堆栈视图的宽度如下:
宽度 = {子视图数量} * {一个子视图的宽度}+ {子视图数量 - 1} * {在属性步骤3中添加的堆栈视图间距}
  1. 当更新或添加/移除子视图时,将此宽度设置为堆栈视图的约束。

现在,以编程方式添加子视图。

英文:

Yes, It's possible.
You can set set the following thing:

Constraints:

  1. Add some height constraint that you want.
  2. Add minimum width to stack view.
  3. Add X and Y position to stack view.

将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

StackView Properties:

  1. Set alignment to fill.
  2. Set distribution to fill equally.
  3. Add some spacing, I've added 5.
    将视图添加到UIStackView中,并在屏幕宽度不足时使它们缩小。

Code:

  1. Take IBOutlet of stack view width in UIViewController class.
  2. Calculate width of stack view as:
width = ({number of subviews} * {width of one subview}) + ({number of subviews - 1} * {stack view spacing added in step 3 of properties})
  1. Set this width to constraint of stack view when update or add remove on subviews.

Now, add subviews programmatically.

huangapple
  • 本文由 发表于 2023年5月29日 10:50:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76354416.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定