UISlider 在 UIStackView 中无法正常工作
UISlider in not working properly in UIStackView
让我解释一下我想要实现的目标。我想在 UIStackView 和 UIScrollView 中创建一个滑块和水平按钮列表,以便按钮可以滚动,然后将 UISlider 和 UIScrollview 放置在垂直 UIStackView 中。但问题是我可以滚动 UISlider 但按钮水平方向似乎卡住或与 UIScrolView 水平方向重叠并且它不起作用我尝试了一切但无法修复它。我想以编程方式进行。任何帮助都非常有用
class ViewController: UIViewController {
private var stackView: UIStackView!
private var stackViewNew: UIStackView!
let x: CGFloat = 10
let width: CGFloat = UIScreen.main.bounds.width - 20
var y: CGFloat = 10
var i = 0
let step:Float=10
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = true
v.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 200)
return v
}()
private var stackViewFilter: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = true
v.axis = .vertical
v.backgroundColor = .black
v.alpha = 0.8
v.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 330)
v.frame.origin = CGPoint(x:0 , y: UIScreen.main.bounds.height - 330)
v.distribution = .equalSpacing
v.spacing = 10.0
return v
}()
let horizontalStackView : UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = true
v.axis = .horizontal
v.backgroundColor = .systemPink
v.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 200)
v.distribution = .equalSpacing
v.spacing = 10.0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
createBottomFilter()
}
@objc func createBottomFilter(){
/*---------- Slider Section ----------*/
let mySlider = UISlider(frame:CGRect(x: 40, y: 10, width: 200, height: 60))
mySlider.minimumValue = 0
mySlider.maximumValue = 100
mySlider.isContinuous = true
mySlider.tintColor = UIColor.green
mySlider.addTarget(self, action: #selector(self.sliderValueDidChange(_:)), for: .valueChanged)
mySlider.translatesAutoresizingMaskIntoConstraints = true
UIView.animate(withDuration: 0.8) {
mySlider.setValue(80.0, animated: true)
}
self.view.addSubview(stackViewFilter)
stackViewFilter.addArrangedSubview(mySlider)
stackViewFilter.addArrangedSubview(scrollView)
self.view.addSubview(scrollView)
mySlider.leadingAnchor.constraint(equalTo: stackViewFilter.leadingAnchor, constant: 8).isActive = true
mySlider.trailingAnchor.constraint(equalTo: stackViewFilter.trailingAnchor, constant: 8).isActive = true
mySlider.topAnchor.constraint(equalTo: stackViewFilter.bottomAnchor, constant: 10).isActive = true
constraintBottom = mySlider.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: 40)
constraintBottom?.isActive = true
scrollView.leftAnchor.constraint(equalTo: stackViewFilter.leftAnchor, constant: 0.0).isActive = true
scrollView.topAnchor.constraint(equalTo: mySlider.bottomAnchor, constant: 8.0).isActive = true
scrollView.rightAnchor.constraint(equalTo: stackViewFilter.rightAnchor, constant: 80.0).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 8.0).isActive = true
// add the stack view to the scroll view
scrollView.addSubview(horizontalStackView)
horizontalStackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0.0).isActive = true
horizontalStackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0.0).isActive = true
horizontalStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -30.0).isActive = true
let b = generateButton(title: "Btn 1", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b.translatesAutoresizingMaskIntoConstraints = true
let b1 = generateButton(title: "Btn 2", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b1.translatesAutoresizingMaskIntoConstraints = true
let b2 = generateButton(title: "Btn 3", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b2.translatesAutoresizingMaskIntoConstraints = true
let b3 = generateButton(title: "Btn 4", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b3.translatesAutoresizingMaskIntoConstraints = true
let b4 = generateButton(title: "Btn 5", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b4.translatesAutoresizingMaskIntoConstraints = true
let b5 = generateButton(title: "Btn 6", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b5.translatesAutoresizingMaskIntoConstraints = true
horizontalStackView.addArrangedSubview(b)
horizontalStackView.addArrangedSubview(b1)
horizontalStackView.addArrangedSubview(b2)
horizontalStackView.addArrangedSubview(b3)
horizontalStackView.addArrangedSubview(b4)
horizontalStackView.addArrangedSubview(b5)
horizontalStackView.alignment = .center
}
@objc func generateButton(title: String, selectedTitle: String? = nil, iconName: String, scaledToSize newSize: CGSize) -> UIButton {
let iconName: UIImage? = imageWithImage(UIImage(named: iconName), scaledToSize:CGSize(width: newSize.width, height: newSize.height))
iconName?.withTintColor(.white)
let button = UIButton.vertical(padding: 3)
button.frame = CGRect(x: x, y: y, width: width, height: 80)
button.setImage(iconName, for: .normal)
button.layer.zPosition = 1
button.setTitle(title, for: .normal)
button.setTitle(selectedTitle, for: .selected)
self.view.addSubview(button)
i += 1
y += button.frame.height
return button
}
}
class VerticalButton: UIButton {
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let titleRect = super.titleRect(forContentRect: contentRect)
let imageRect = super.imageRect(forContentRect: contentRect)
return CGRect(x: 0,
y: contentRect.height - (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2 - titleRect.size.height,
width: contentRect.width,
height: titleRect.height)
}
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let imageRect = super.imageRect(forContentRect: contentRect)
let titleRect = self.titleRect(forContentRect: contentRect)
return CGRect(x: contentRect.width/2.0 - imageRect.width/2.0,
y: (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2,
width: imageRect.width,
height: imageRect.height )
}
private let padding: CGFloat
init(padding: CGFloat) {
self.padding = padding
super.init(frame: .zero)
self.titleLabel?.textAlignment = .center
}
required init?(coder aDecoder: NSCoder) { fatalError() }
}
extension UIButton {
static func vertical(padding: CGFloat) -> UIButton {
return VerticalButton(padding: padding)
}}
有点难,因为你没有展示你想要实现的目标的图像。
此外,您的代码缺少 imageWithImage(...)
函数,因此我们无法 运行 直接查看您得到的结果。
但是,这可能对您有所帮助...
您做错了很多事 -- 将显式框架设置与堆栈视图(使用自动布局)混在一起;在错误的地方添加视图;在不应该的地方设置约束;等等
她的代码是您希望接近您所追求的代码。我添加了注释来解释不应该存在的内容,并注释掉了您现有的代码,以便您可以看到差异:
class ViewController: UIViewController {
var i = 0
// these will not be used
// private var stackView: UIStackView!
// private var stackViewNew: UIStackView!
// let x: CGFloat = 10
// let width: CGFloat = UIScreen.main.bounds.width - 20
// var y: CGFloat = 10
// let step:Float=10
let scrollView: UIScrollView = {
let v = UIScrollView()
// we will want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
private var stackViewFilter: UIStackView = {
let v = UIStackView()
// we will want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.backgroundColor = .black
v.alpha = 0.8
// use .fill instead of .equalSpacing
v.distribution = .fill
v.spacing = 10.0
return v
}()
let horizontalStackView : UIStackView = {
let v = UIStackView()
// we will want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .horizontal
v.backgroundColor = .systemPink
// you want the buttons to be equal sizes,
// so use .fillEqually instead of .equalSpacing
v.distribution = .fill
v.spacing = 10.0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
createBottomFilter()
}
@objc func createBottomFilter(){
/*---------- Slider Section ----------*/
// we will want to use auto-layout
// so no need to set a frame here
//let mySlider = UISlider(frame:CGRect(x: 40, y: 10, width: 200, height: 60))
let mySlider = UISlider()
mySlider.translatesAutoresizingMaskIntoConstraints = false
mySlider.minimumValue = 0
mySlider.maximumValue = 100
mySlider.isContinuous = true
mySlider.tintColor = UIColor.green
mySlider.addTarget(self, action: #selector(self.sliderValueDidChange(_:)), for: .valueChanged)
UIView.animate(withDuration: 0.8) {
mySlider.setValue(80.0, animated: true)
}
// respect safe-area
let g = view.safeAreaLayoutGuide
self.view.addSubview(stackViewFilter)
// constrain stackViewFilter
NSLayoutConstraint.activate([
stackViewFilter.leadingAnchor.constraint(equalTo: g.leadingAnchor),
stackViewFilter.trailingAnchor.constraint(equalTo: g.trailingAnchor),
stackViewFilter.bottomAnchor.constraint(equalTo: g.bottomAnchor),
stackViewFilter.heightAnchor.constraint(equalToConstant: 330.0),
])
stackViewFilter.addArrangedSubview(mySlider)
stackViewFilter.addArrangedSubview(scrollView)
// just added scrollView as an arrangedSubview of stackViewFilter
// so don't add it to the view
//self.view.addSubview(scrollView)
// slider is in a stack view, so don't set any positioning constraints
//mySlider.leadingAnchor.constraint(equalTo: stackViewFilter.leadingAnchor, constant: 8).isActive = true
//mySlider.trailingAnchor.constraint(equalTo: stackViewFilter.trailingAnchor, constant: 8).isActive = true
//mySlider.topAnchor.constraint(equalTo: stackViewFilter.bottomAnchor, constant: 10).isActive = true
//constraintBottom = mySlider.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: 40)
//constraintBottom?.isActive = true
// scrollView is in a stack view, so don't set any positioning constraints
//scrollView.leftAnchor.constraint(equalTo: stackViewFilter.leftAnchor, constant: 0.0).isActive = true
//scrollView.topAnchor.constraint(equalTo: mySlider.bottomAnchor, constant: 8.0).isActive = true
//scrollView.rightAnchor.constraint(equalTo: stackViewFilter.rightAnchor, constant: 80.0).isActive = true
//scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 8.0).isActive = true
// but we can set the scrollView's height constraint here
scrollView.heightAnchor.constraint(equalToConstant: 200.0).isActive = true
// add the stack view to the scroll view
scrollView.addSubview(horizontalStackView)
// constrain scrollView contents to the scrollView's contentLayoutGuide
//horizontalStackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0.0).isActive = true
//horizontalStackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0.0).isActive = true
//horizontalStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -30.0).isActive = true
NSLayoutConstraint.activate([
horizontalStackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
horizontalStackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
horizontalStackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
horizontalStackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: 30.0),
])
// views added to stackView as arrangedSubview automatically use auto-layout
// so no sense setting .translatesAutoresizingMaskIntoConstraints = true
let b = generateButton(title: "Btn 1", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b.translatesAutoresizingMaskIntoConstraints = true
let b1 = generateButton(title: "Btn 2", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b1.translatesAutoresizingMaskIntoConstraints = true
let b2 = generateButton(title: "Btn 3", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b2.translatesAutoresizingMaskIntoConstraints = true
let b3 = generateButton(title: "Btn 4", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b3.translatesAutoresizingMaskIntoConstraints = true
let b4 = generateButton(title: "Btn 5", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b4.translatesAutoresizingMaskIntoConstraints = true
let b5 = generateButton(title: "Btn 6", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b5.translatesAutoresizingMaskIntoConstraints = true
horizontalStackView.addArrangedSubview(b)
horizontalStackView.addArrangedSubview(b1)
horizontalStackView.addArrangedSubview(b2)
horizontalStackView.addArrangedSubview(b3)
horizontalStackView.addArrangedSubview(b4)
horizontalStackView.addArrangedSubview(b5)
// alignment should be .fill, not .center
horizontalStackView.alignment = .fill
// because we set horizontalStackView.distribution = .fillEqually
// we only need to set a width constraint on the first button
b.widthAnchor.constraint(equalToConstant: 90.0).isActive = true
// buttons should all be 90x90 ?
[b, b1, b2, b3, b4, b5].forEach { btn in
btn.heightAnchor.constraint(equalTo: btn.widthAnchor).isActive = true
}
}
@objc func generateButton(title: String, selectedTitle: String? = nil, iconName: String, scaledToSize newSize: CGSize) -> UIButton {
let iconName: UIImage? = imageWithImage(UIImage(named: iconName), scaledToSize:CGSize(width: newSize.width, height: newSize.height))
iconName?.withTintColor(.white)
let button = UIButton.vertical(padding: 3)
// buttons in stack view will use auto-layout,
// so no need to set frames here
//button.frame = CGRect(x: x, y: y, width: width, height: 80)
button.setImage(iconName, for: .normal)
button.layer.zPosition = 1
button.setTitle(title, for: .normal)
button.setTitle(selectedTitle, for: .selected)
// button will be added to stack view
//self.view.addSubview(button)
i += 1
// not sure why this was here to begin with...
// you want a horizontal row of buttons, so changing the
// y position makes no sense
//y += button.frame.height
return button
}
}
class VerticalButton: UIButton {
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let titleRect = super.titleRect(forContentRect: contentRect)
let imageRect = super.imageRect(forContentRect: contentRect)
return CGRect(x: 0,
y: contentRect.height - (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2 - titleRect.size.height,
width: contentRect.width,
height: titleRect.height)
}
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let imageRect = super.imageRect(forContentRect: contentRect)
let titleRect = self.titleRect(forContentRect: contentRect)
return CGRect(x: contentRect.width/2.0 - imageRect.width/2.0,
y: (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2,
width: imageRect.width,
height: imageRect.height )
}
private let padding: CGFloat
init(padding: CGFloat) {
self.padding = padding
super.init(frame: .zero)
self.titleLabel?.textAlignment = .center
}
required init?(coder aDecoder: NSCoder) { fatalError() }
}
extension UIButton {
static func vertical(padding: CGFloat) -> UIButton {
return VerticalButton(padding: padding)
}
}
这是它的外观,使用系统“文档”图像作为按钮,因为我不知道你用 iconName
做什么...水平按钮 可以 滚动:
如果这接近您的要求,您应该能够在查看代码后调整值。
让我解释一下我想要实现的目标。我想在 UIStackView 和 UIScrollView 中创建一个滑块和水平按钮列表,以便按钮可以滚动,然后将 UISlider 和 UIScrollview 放置在垂直 UIStackView 中。但问题是我可以滚动 UISlider 但按钮水平方向似乎卡住或与 UIScrolView 水平方向重叠并且它不起作用我尝试了一切但无法修复它。我想以编程方式进行。任何帮助都非常有用
class ViewController: UIViewController {
private var stackView: UIStackView!
private var stackViewNew: UIStackView!
let x: CGFloat = 10
let width: CGFloat = UIScreen.main.bounds.width - 20
var y: CGFloat = 10
var i = 0
let step:Float=10
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = true
v.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 200)
return v
}()
private var stackViewFilter: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = true
v.axis = .vertical
v.backgroundColor = .black
v.alpha = 0.8
v.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 330)
v.frame.origin = CGPoint(x:0 , y: UIScreen.main.bounds.height - 330)
v.distribution = .equalSpacing
v.spacing = 10.0
return v
}()
let horizontalStackView : UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = true
v.axis = .horizontal
v.backgroundColor = .systemPink
v.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 200)
v.distribution = .equalSpacing
v.spacing = 10.0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
createBottomFilter()
}
@objc func createBottomFilter(){
/*---------- Slider Section ----------*/
let mySlider = UISlider(frame:CGRect(x: 40, y: 10, width: 200, height: 60))
mySlider.minimumValue = 0
mySlider.maximumValue = 100
mySlider.isContinuous = true
mySlider.tintColor = UIColor.green
mySlider.addTarget(self, action: #selector(self.sliderValueDidChange(_:)), for: .valueChanged)
mySlider.translatesAutoresizingMaskIntoConstraints = true
UIView.animate(withDuration: 0.8) {
mySlider.setValue(80.0, animated: true)
}
self.view.addSubview(stackViewFilter)
stackViewFilter.addArrangedSubview(mySlider)
stackViewFilter.addArrangedSubview(scrollView)
self.view.addSubview(scrollView)
mySlider.leadingAnchor.constraint(equalTo: stackViewFilter.leadingAnchor, constant: 8).isActive = true
mySlider.trailingAnchor.constraint(equalTo: stackViewFilter.trailingAnchor, constant: 8).isActive = true
mySlider.topAnchor.constraint(equalTo: stackViewFilter.bottomAnchor, constant: 10).isActive = true
constraintBottom = mySlider.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: 40)
constraintBottom?.isActive = true
scrollView.leftAnchor.constraint(equalTo: stackViewFilter.leftAnchor, constant: 0.0).isActive = true
scrollView.topAnchor.constraint(equalTo: mySlider.bottomAnchor, constant: 8.0).isActive = true
scrollView.rightAnchor.constraint(equalTo: stackViewFilter.rightAnchor, constant: 80.0).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 8.0).isActive = true
// add the stack view to the scroll view
scrollView.addSubview(horizontalStackView)
horizontalStackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0.0).isActive = true
horizontalStackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0.0).isActive = true
horizontalStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -30.0).isActive = true
let b = generateButton(title: "Btn 1", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b.translatesAutoresizingMaskIntoConstraints = true
let b1 = generateButton(title: "Btn 2", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b1.translatesAutoresizingMaskIntoConstraints = true
let b2 = generateButton(title: "Btn 3", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b2.translatesAutoresizingMaskIntoConstraints = true
let b3 = generateButton(title: "Btn 4", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b3.translatesAutoresizingMaskIntoConstraints = true
let b4 = generateButton(title: "Btn 5", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b4.translatesAutoresizingMaskIntoConstraints = true
let b5 = generateButton(title: "Btn 6", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
b5.translatesAutoresizingMaskIntoConstraints = true
horizontalStackView.addArrangedSubview(b)
horizontalStackView.addArrangedSubview(b1)
horizontalStackView.addArrangedSubview(b2)
horizontalStackView.addArrangedSubview(b3)
horizontalStackView.addArrangedSubview(b4)
horizontalStackView.addArrangedSubview(b5)
horizontalStackView.alignment = .center
}
@objc func generateButton(title: String, selectedTitle: String? = nil, iconName: String, scaledToSize newSize: CGSize) -> UIButton {
let iconName: UIImage? = imageWithImage(UIImage(named: iconName), scaledToSize:CGSize(width: newSize.width, height: newSize.height))
iconName?.withTintColor(.white)
let button = UIButton.vertical(padding: 3)
button.frame = CGRect(x: x, y: y, width: width, height: 80)
button.setImage(iconName, for: .normal)
button.layer.zPosition = 1
button.setTitle(title, for: .normal)
button.setTitle(selectedTitle, for: .selected)
self.view.addSubview(button)
i += 1
y += button.frame.height
return button
}
}
class VerticalButton: UIButton {
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let titleRect = super.titleRect(forContentRect: contentRect)
let imageRect = super.imageRect(forContentRect: contentRect)
return CGRect(x: 0,
y: contentRect.height - (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2 - titleRect.size.height,
width: contentRect.width,
height: titleRect.height)
}
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let imageRect = super.imageRect(forContentRect: contentRect)
let titleRect = self.titleRect(forContentRect: contentRect)
return CGRect(x: contentRect.width/2.0 - imageRect.width/2.0,
y: (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2,
width: imageRect.width,
height: imageRect.height )
}
private let padding: CGFloat
init(padding: CGFloat) {
self.padding = padding
super.init(frame: .zero)
self.titleLabel?.textAlignment = .center
}
required init?(coder aDecoder: NSCoder) { fatalError() }
}
extension UIButton {
static func vertical(padding: CGFloat) -> UIButton {
return VerticalButton(padding: padding)
}}
有点难,因为你没有展示你想要实现的目标的图像。
此外,您的代码缺少 imageWithImage(...)
函数,因此我们无法 运行 直接查看您得到的结果。
但是,这可能对您有所帮助...
您做错了很多事 -- 将显式框架设置与堆栈视图(使用自动布局)混在一起;在错误的地方添加视图;在不应该的地方设置约束;等等
她的代码是您希望接近您所追求的代码。我添加了注释来解释不应该存在的内容,并注释掉了您现有的代码,以便您可以看到差异:
class ViewController: UIViewController {
var i = 0
// these will not be used
// private var stackView: UIStackView!
// private var stackViewNew: UIStackView!
// let x: CGFloat = 10
// let width: CGFloat = UIScreen.main.bounds.width - 20
// var y: CGFloat = 10
// let step:Float=10
let scrollView: UIScrollView = {
let v = UIScrollView()
// we will want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
private var stackViewFilter: UIStackView = {
let v = UIStackView()
// we will want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.backgroundColor = .black
v.alpha = 0.8
// use .fill instead of .equalSpacing
v.distribution = .fill
v.spacing = 10.0
return v
}()
let horizontalStackView : UIStackView = {
let v = UIStackView()
// we will want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .horizontal
v.backgroundColor = .systemPink
// you want the buttons to be equal sizes,
// so use .fillEqually instead of .equalSpacing
v.distribution = .fill
v.spacing = 10.0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
createBottomFilter()
}
@objc func createBottomFilter(){
/*---------- Slider Section ----------*/
// we will want to use auto-layout
// so no need to set a frame here
//let mySlider = UISlider(frame:CGRect(x: 40, y: 10, width: 200, height: 60))
let mySlider = UISlider()
mySlider.translatesAutoresizingMaskIntoConstraints = false
mySlider.minimumValue = 0
mySlider.maximumValue = 100
mySlider.isContinuous = true
mySlider.tintColor = UIColor.green
mySlider.addTarget(self, action: #selector(self.sliderValueDidChange(_:)), for: .valueChanged)
UIView.animate(withDuration: 0.8) {
mySlider.setValue(80.0, animated: true)
}
// respect safe-area
let g = view.safeAreaLayoutGuide
self.view.addSubview(stackViewFilter)
// constrain stackViewFilter
NSLayoutConstraint.activate([
stackViewFilter.leadingAnchor.constraint(equalTo: g.leadingAnchor),
stackViewFilter.trailingAnchor.constraint(equalTo: g.trailingAnchor),
stackViewFilter.bottomAnchor.constraint(equalTo: g.bottomAnchor),
stackViewFilter.heightAnchor.constraint(equalToConstant: 330.0),
])
stackViewFilter.addArrangedSubview(mySlider)
stackViewFilter.addArrangedSubview(scrollView)
// just added scrollView as an arrangedSubview of stackViewFilter
// so don't add it to the view
//self.view.addSubview(scrollView)
// slider is in a stack view, so don't set any positioning constraints
//mySlider.leadingAnchor.constraint(equalTo: stackViewFilter.leadingAnchor, constant: 8).isActive = true
//mySlider.trailingAnchor.constraint(equalTo: stackViewFilter.trailingAnchor, constant: 8).isActive = true
//mySlider.topAnchor.constraint(equalTo: stackViewFilter.bottomAnchor, constant: 10).isActive = true
//constraintBottom = mySlider.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: 40)
//constraintBottom?.isActive = true
// scrollView is in a stack view, so don't set any positioning constraints
//scrollView.leftAnchor.constraint(equalTo: stackViewFilter.leftAnchor, constant: 0.0).isActive = true
//scrollView.topAnchor.constraint(equalTo: mySlider.bottomAnchor, constant: 8.0).isActive = true
//scrollView.rightAnchor.constraint(equalTo: stackViewFilter.rightAnchor, constant: 80.0).isActive = true
//scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 8.0).isActive = true
// but we can set the scrollView's height constraint here
scrollView.heightAnchor.constraint(equalToConstant: 200.0).isActive = true
// add the stack view to the scroll view
scrollView.addSubview(horizontalStackView)
// constrain scrollView contents to the scrollView's contentLayoutGuide
//horizontalStackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0.0).isActive = true
//horizontalStackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0.0).isActive = true
//horizontalStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -30.0).isActive = true
NSLayoutConstraint.activate([
horizontalStackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
horizontalStackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
horizontalStackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
horizontalStackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: 30.0),
])
// views added to stackView as arrangedSubview automatically use auto-layout
// so no sense setting .translatesAutoresizingMaskIntoConstraints = true
let b = generateButton(title: "Btn 1", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b.translatesAutoresizingMaskIntoConstraints = true
let b1 = generateButton(title: "Btn 2", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b1.translatesAutoresizingMaskIntoConstraints = true
let b2 = generateButton(title: "Btn 3", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b2.translatesAutoresizingMaskIntoConstraints = true
let b3 = generateButton(title: "Btn 4", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b3.translatesAutoresizingMaskIntoConstraints = true
let b4 = generateButton(title: "Btn 5", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b4.translatesAutoresizingMaskIntoConstraints = true
let b5 = generateButton(title: "Btn 6", selectedTitle: "Filter \(i)", iconName: "hellen", scaledToSize:CGSize(width: 90.0, height: 90.0))
//b5.translatesAutoresizingMaskIntoConstraints = true
horizontalStackView.addArrangedSubview(b)
horizontalStackView.addArrangedSubview(b1)
horizontalStackView.addArrangedSubview(b2)
horizontalStackView.addArrangedSubview(b3)
horizontalStackView.addArrangedSubview(b4)
horizontalStackView.addArrangedSubview(b5)
// alignment should be .fill, not .center
horizontalStackView.alignment = .fill
// because we set horizontalStackView.distribution = .fillEqually
// we only need to set a width constraint on the first button
b.widthAnchor.constraint(equalToConstant: 90.0).isActive = true
// buttons should all be 90x90 ?
[b, b1, b2, b3, b4, b5].forEach { btn in
btn.heightAnchor.constraint(equalTo: btn.widthAnchor).isActive = true
}
}
@objc func generateButton(title: String, selectedTitle: String? = nil, iconName: String, scaledToSize newSize: CGSize) -> UIButton {
let iconName: UIImage? = imageWithImage(UIImage(named: iconName), scaledToSize:CGSize(width: newSize.width, height: newSize.height))
iconName?.withTintColor(.white)
let button = UIButton.vertical(padding: 3)
// buttons in stack view will use auto-layout,
// so no need to set frames here
//button.frame = CGRect(x: x, y: y, width: width, height: 80)
button.setImage(iconName, for: .normal)
button.layer.zPosition = 1
button.setTitle(title, for: .normal)
button.setTitle(selectedTitle, for: .selected)
// button will be added to stack view
//self.view.addSubview(button)
i += 1
// not sure why this was here to begin with...
// you want a horizontal row of buttons, so changing the
// y position makes no sense
//y += button.frame.height
return button
}
}
class VerticalButton: UIButton {
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let titleRect = super.titleRect(forContentRect: contentRect)
let imageRect = super.imageRect(forContentRect: contentRect)
return CGRect(x: 0,
y: contentRect.height - (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2 - titleRect.size.height,
width: contentRect.width,
height: titleRect.height)
}
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let imageRect = super.imageRect(forContentRect: contentRect)
let titleRect = self.titleRect(forContentRect: contentRect)
return CGRect(x: contentRect.width/2.0 - imageRect.width/2.0,
y: (contentRect.height - padding - imageRect.size.height - titleRect.size.height) / 2,
width: imageRect.width,
height: imageRect.height )
}
private let padding: CGFloat
init(padding: CGFloat) {
self.padding = padding
super.init(frame: .zero)
self.titleLabel?.textAlignment = .center
}
required init?(coder aDecoder: NSCoder) { fatalError() }
}
extension UIButton {
static func vertical(padding: CGFloat) -> UIButton {
return VerticalButton(padding: padding)
}
}
这是它的外观,使用系统“文档”图像作为按钮,因为我不知道你用 iconName
做什么...水平按钮 可以 滚动:
如果这接近您的要求,您应该能够在查看代码后调整值。