Swift中如何实现垂直标签栏?修正现有布局问题
问题解决:实现目标布局并修正旋转导致的布局错位
核心问题分析
直接通过transform旋转视图会破坏AutoLayout的布局逻辑——AutoLayout始终基于视图原始未旋转的尺寸计算约束,旋转后视图的实际显示尺寸与约束尺寸不匹配,最终导致布局错位。
推荐解决方案:避免视图旋转,直接调整布局结构
通过调整文字排版和StackView的排列方向,无需旋转即可实现目标布局,同时完全适配AutoLayout:
1. 修改左侧竖排Label的实现
不用旋转整个Label,而是让文字自然竖排:
let label2 = UILabel() label2.text = "Label" label2.backgroundColor = .red label2.textColor = .white label2.textAlignment = .center label2.font = UIFont.systemFont(ofSize: 14) // 将文字拆分为单个字符换行,实现竖排效果 label2.text = "Label".map { String($0) }.joined(separator: "\n") label2.numberOfLines = 0 label2.translatesAutoresizingMaskIntoConstraints = false
2. 重构右侧彩色标签的StackView
直接使用垂直StackView排列彩色标签,无需旋转:
var buttonArray = [UILabel]() for (myKey, myValue) in colorDictionary { buttonArray.append(colorButton(withColor: myValue, title: myKey)) } // 改用垂直StackView,自然实现上下排列 let verticalStack = UIStackView(arrangedSubviews: buttonArray) verticalStack.axis = .vertical verticalStack.distribution = .fillEqually verticalStack.alignment = .fill verticalStack.spacing = 2 // 增加标签间的间距,匹配目标样式 verticalStack.translatesAutoresizingMaskIntoConstraints = false
3. 调整主StackView约束
let mainStackView = UIStackView(arrangedSubviews: [label2, verticalStack]) mainStackView.axis = .horizontal mainStackView.spacing = 8 // 左右模块的间距 mainStackView.translatesAutoresizingMaskIntoConstraints = false mainContainer.addSubview(mainStackView) NSLayoutConstraint.activate([ mainStackView.topAnchor.constraint(equalTo: mainContainer.topAnchor, constant: 5), mainStackView.leftAnchor.constraint(equalTo: mainContainer.leftAnchor, constant: 20), mainStackView.rightAnchor.constraint(equalTo: mainContainer.rightAnchor, constant: -20), mainStackView.bottomAnchor.constraint(equalTo: mainContainer.bottomAnchor, constant: -5), label2.widthAnchor.constraint(equalToConstant: 40) // 固定左侧标签宽度 ])
4. 优化colorButton方法
func colorButton(withColor color: UIColor, title: String) -> UILabel{ let newButton = UILabel() newButton.backgroundColor = color newButton.text = title newButton.textAlignment = .center newButton.textColor = .white newButton.font = UIFont.systemFont(ofSize: 14) newButton.numberOfLines = 1 return newButton }
备选方案:如果必须使用视图旋转
若你坚持要通过旋转实现,需要用容器视图包裹旋转后的元素,手动适配容器尺寸与旋转后视图的尺寸:
// 左侧Label的容器 let labelContainer = UIView() labelContainer.translatesAutoresizingMaskIntoConstraints = false let label2 = UILabel() label2.text = "Label" label2.backgroundColor = .red label2.textColor = .white label2.textAlignment = .center label2.translatesAutoresizingMaskIntoConstraints = false labelContainer.addSubview(label2) label2.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2) // 让容器尺寸匹配旋转后的Label尺寸 NSLayoutConstraint.activate([ label2.centerXAnchor.constraint(equalTo: labelContainer.centerXAnchor), label2.centerYAnchor.constraint(equalTo: labelContainer.centerYAnchor), labelContainer.widthAnchor.constraint(equalTo: label2.heightAnchor), labelContainer.heightAnchor.constraint(equalTo: label2.widthAnchor) ]) // 右侧Stack的容器 let stackContainer = UIView() stackContainer.translatesAutoresizingMaskIntoConstraints = false let horizontalStack = UIStackView(arrangedSubviews: buttonArray) horizontalStack.axis = .horizontal horizontalStack.distribution = .fillEqually horizontalStack.alignment = .fill horizontalStack.spacing = 2 horizontalStack.translatesAutoresizingMaskIntoConstraints = false horizontalStack.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2) stackContainer.addSubview(horizontalStack) // 让容器尺寸匹配旋转后的Stack尺寸 NSLayoutConstraint.activate([ horizontalStack.centerXAnchor.constraint(equalTo: stackContainer.centerXAnchor), horizontalStack.centerYAnchor.constraint(equalTo: stackContainer.centerYAnchor), stackContainer.widthAnchor.constraint(equalTo: horizontalStack.heightAnchor), stackContainer.heightAnchor.constraint(equalTo: horizontalStack.widthAnchor) ]) // 主Stack布局 let mainStackView = UIStackView(arrangedSubviews: [labelContainer, stackContainer]) mainStackView.axis = .horizontal mainStackView.spacing = 8 mainStackView.translatesAutoresizingMaskIntoConstraints = false mainContainer.addSubview(mainStackView) NSLayoutConstraint.activate([ mainStackView.topAnchor.constraint(equalTo: mainContainer.topAnchor, constant: 5), mainStackView.leftAnchor.constraint(equalTo: mainContainer.leftAnchor, constant: 20), mainStackView.rightAnchor.constraint(equalTo: mainContainer.rightAnchor, constant: -20), mainStackView.bottomAnchor.constraint(equalTo: mainContainer.bottomAnchor, constant: -5), labelContainer.widthAnchor.constraint(equalToConstant: 40) ])
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

