[英]Fitting UIStackView in UIScrollView programmatically
我将stackView 添加到scrollView。 我将 scrollView 的宽度、X 和 Y 约束设置为与主视图相同,固定高度为 50。对于堆栈约束,我做了同样的事情,但相对于 scrollView 而不是视图。
我的问题是当我将 UIImageViews 添加到我的堆栈时(所有图像都是 50 x 50)。 我需要堆栈仅显示前三个 UIImageView,如果超过 3 个则水平滚动。到目前为止,我的堆栈始终显示所有 UIImageView。
任何建议表示赞赏。 现在已经为此工作了2天。 谢谢!
你可能想做的事...
创建一个“选项卡视图”——这是一个带有50 x 50
居中图像视图、圆角顶角和 1-pt 轮廓的示例:
我们可以用这个简单的 class 创建它:
class MyTabView: UIView {
let imgView = UIImageView()
init(with image: UIImage) {
super.init(frame: .zero)
imgView.image = image
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
imgView.translatesAutoresizingMaskIntoConstraints = false
// light gray background
backgroundColor = UIColor(white: 0.9, alpha: 1.0)
addSubview(imgView)
NSLayoutConstraint.activate([
// centered
imgView.centerXAnchor.constraint(equalTo: centerXAnchor),
imgView.centerYAnchor.constraint(equalTo: centerYAnchor),
// 50x50
imgView.widthAnchor.constraint(equalToConstant: 50.0),
imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor),
])
// a little "styling" for the "tab"
clipsToBounds = true
layer.cornerRadius = 12
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
layer.borderWidth = 1
layer.borderColor = UIColor.darkGray.cgColor
}
}
对于我们添加到堆栈视图的每个“选项卡”,我们将设置其宽度约束等于滚动视图的框架布局指南widthAnchor
multiplier: 1.0 / 3.0
。 这样每个“标签视图”将是滚动视图宽度的 1/3:
使用 1、2 或 3 个“标签”将不会有水平滚动,因为它们都适合框架。
一旦我们有超过 3 个“选项卡”,堆栈视图的宽度将超过框架的宽度,我们将进行水平滚动:
这是我用于此的视图 controller。 它创建 9 个“标签图像”......从一个“标签”开始......每次点击都会添加一个“标签”,直到我们拥有全部 9 个标签,此时每次点击都会删除一个“标签”:
class StackAsTabsViewController: UIViewController {
let stackView: UIStackView = {
let v = UIStackView()
v.axis = .horizontal
v.distribution = .fill
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
// a label to show what's going on
let statusLabel: UILabel = {
let v = UILabel()
v.numberOfLines = 0
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
// array to hold our "tab" images
var images: [UIImage] = []
// we'll add a "tab" on each tap
// until we reach the end of the images array
// then we'll remove a "tab" on each tap
// until we're back to a single "tab"
var isAdding: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
// add the "status" label
view.addSubview(statusLabel)
// add stackView to scrollView
scrollView.addSubview(stackView)
// add scrollView to view
view.addSubview(scrollView)
// respect safe area
let g = view.safeAreaLayoutGuide
// scrollView Content and Frame Layout Guides
let contentG = scrollView.contentLayoutGuide
let frameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain scrollView Top / Leading / Trailing
scrollView.topAnchor.constraint(equalTo: g.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// height = 58 (image will be 50x50, so a little top and bottom padding)
scrollView.heightAnchor.constraint(equalToConstant: 58.0),
// constrain stackView all 4 sides to scrollView Content Layout Guide
stackView.topAnchor.constraint(equalTo: contentG.topAnchor),
stackView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor),
// stackView Height equal to scrollView Frame Height
stackView.heightAnchor.constraint(equalTo: frameG.heightAnchor),
// statusLabel in the middle of the view
statusLabel.topAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 40.0),
statusLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
statusLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0)
])
// let's create 9 images using SF Symbols
for i in 1...9 {
guard let img = UIImage(systemName: "\(i).circle.fill") else {
fatalError("Could not create images!!!")
}
images.append(img)
}
// add the first "tab view"
self.updateTabs()
// tap anywhere in the view
let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
view.addGestureRecognizer(t)
}
@objc func gotTap(_ g: UITapGestureRecognizer) -> Void {
updateTabs()
}
func updateTabs() -> Void {
if isAdding {
// get the next image from the array
let img = images[stackView.arrangedSubviews.count]
// create a "tab view"
let tab = MyTabView(with: img)
// add it to the stackView
stackView.addArrangedSubview(tab)
let frameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// each "tab view" is 1/3rd the width of the scroll view frame
tab.widthAnchor.constraint(equalTo: frameG.widthAnchor, multiplier: 1.0 / 3.0),
// each "tab view" is the same height as the scroll view frame
tab.heightAnchor.constraint(equalTo: frameG.heightAnchor),
])
} else {
stackView.arrangedSubviews.last?.removeFromSuperview()
}
if stackView.arrangedSubviews.count == 1 {
isAdding = true
} else if stackView.arrangedSubviews.count == images.count {
isAdding = false
}
updateStatusLabel()
}
func updateStatusLabel() -> Void {
// we'll do this async, to make sure the views have been updated
DispatchQueue.main.async {
let numTabs = self.stackView.arrangedSubviews.count
var str = ""
if self.isAdding {
str += "Tap anywhere to ADD a tab"
} else {
str += "Tap anywhere to REMOVE a tab"
}
str += "\n\n"
str += "Number of tabs: \(numTabs)"
str += "\n\n"
if numTabs > 3 {
str += "Tabs WILL scroll"
} else {
str += "Tabs will NOT scroll"
}
self.statusLabel.text = str
}
}
}
玩它,看看这是不是你想要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.