按钮在编程动态 stackView (Swift) 中变为非活动状态
Posted
技术标签:
【中文标题】按钮在编程动态 stackView (Swift) 中变为非活动状态【英文标题】:Button becomes inactive in programmatic dynamic stackView (Swift) 【发布时间】:2017-07-14 00:07:04 【问题描述】:我正在尝试在Apple's Auto Layout Cookbook 中实现动态堆栈视图的程序化版本。 “添加项目”按钮应该向垂直 stackView 添加新视图,包括删除每个视图的删除按钮。我的编程代码在“添加项目”按钮的 1 次触摸中工作正常,但随后该按钮变为非活动状态。结果,我只能向 stackView 添加 1 个项目。如果我使用删除按钮,“添加项目”会再次激活。我已经包含了一个动画 gif 来说明。
我同时发布了我的程序化代码(有问题)和基于故事板的原始代码(工作正常)。我尝试在 addEntry 函数中放置一个调试断点,但这没有帮助。 -谢谢
编程代码(“添加项目”按钮只能使用一次):
import UIKit
class CodeDynamStackVC: UIViewController
// MARK: Properties
var scrollView = UIScrollView()
var stackView = UIStackView()
var button = UIButton()
// MARK: UIViewController
override func viewDidLoad()
super.viewDidLoad()
// Set up the scrollview
let insets = UIEdgeInsets(top: 20, left: 0.0, bottom: 0.0, right: 0.0)
scrollView.contentInset = insets
scrollView.scrollIndicatorInsets = insets
setupInitialVertStackView()
//setup initial button inside vertical stackView
func setupInitialVertStackView()
// make inital "Add Item" button
button = UIButton(type: .system)
button.setTitle("Add Item", for: .normal)
button.setTitleColor(UIColor.blue, for: .normal)
button.addTarget(self, action: #selector(addEntry), for: .touchUpInside)
//enclose button in a vertical stackView
stackView.addArrangedSubview(button)
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
let viewsDictionary = ["v0":stackView]
let stackView_H = NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary)
let stackView_V = NSLayoutConstraint.constraints(withVisualFormat: "V:|-20-[v0(25)]|", options: NSLayoutFormatOptions(rawValue:0), metrics: nil, views: viewsDictionary)
view.addConstraints(stackView_H)
view.addConstraints(stackView_V)
// MARK: Interface Builder actions
func addEntry()
guard let addButtonContainerView = stackView.arrangedSubviews.last else fatalError("Expected at least one arranged view in the stack view.")
let nextEntryIndex = stackView.arrangedSubviews.count - 1
let offset = CGPoint(x: scrollView.contentOffset.x, y: scrollView.contentOffset.y + addButtonContainerView.bounds.size.height)
let newEntryView = createEntryView()
newEntryView.isHidden = true
stackView.insertArrangedSubview(newEntryView, at: nextEntryIndex)
UIView.animate(withDuration: 0.25, animations:
newEntryView.isHidden = false
self.scrollView.contentOffset = offset
)
func deleteStackView(_ sender: UIButton)
guard let entryView = sender.superview else return
UIView.animate(withDuration: 0.25, animations:
entryView.isHidden = true
, completion: _ in
entryView.removeFromSuperview()
)
// MARK: Convenience
/// Creates a horizontal stackView entry to place within the parent vertical stackView
fileprivate func createEntryView() -> UIView
let date = DateFormatter.localizedString(from: Date(), dateStyle: .short, timeStyle: .none)
let number = UUID().uuidString
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .center
stack.distribution = .fill
stack.spacing = 8
let dateLabel = UILabel()
dateLabel.text = date
dateLabel.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
let numberLabel = UILabel()
numberLabel.text = number
numberLabel.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.caption2)
numberLabel.setContentHuggingPriority(UILayoutPriorityDefaultLow - 1.0, for: .horizontal)
numberLabel.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh - 1.0, for: .horizontal)
let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Del", for: UIControlState())
deleteButton.addTarget(self, action: #selector(DynamStackVC.deleteStackView(_:)), for: .touchUpInside)
stack.addArrangedSubview(dateLabel)
stack.addArrangedSubview(numberLabel)
stack.addArrangedSubview(deleteButton)
return stack
基于故事板的代码(“添加项目”按钮始终有效)
import UIKit
class DynamStackVC: UIViewController
// MARK: Properties
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var stackView: UIStackView!
// MARK: UIViewController
override func viewDidLoad()
super.viewDidLoad()
// Set up the scrollview.
let insets = UIEdgeInsets(top: 20, left: 0.0, bottom: 0.0, right: 0.0)
scrollView.contentInset = insets
scrollView.scrollIndicatorInsets = insets
// MARK: Interface Builder actions
@IBAction func addEntry(_: AnyObject)
guard let addButtonContainerView = stackView.arrangedSubviews.last else fatalError("Expected at least one arranged view in the stack view.")
let nextEntryIndex = stackView.arrangedSubviews.count - 1
let offset = CGPoint(x: scrollView.contentOffset.x, y: scrollView.contentOffset.y + addButtonContainerView.bounds.size.height)
let newEntryView = createEntryView()
newEntryView.isHidden = true
stackView.insertArrangedSubview(newEntryView, at: nextEntryIndex)
UIView.animate(withDuration: 0.25, animations:
newEntryView.isHidden = false
self.scrollView.contentOffset = offset
)
func deleteStackView(_ sender: UIButton)
guard let entryView = sender.superview else return
UIView.animate(withDuration: 0.25, animations:
entryView.isHidden = true
, completion: _ in
entryView.removeFromSuperview()
)
// MARK: Convenience
/// Creates a horizontal stack view entry to place within the parent `stackView`.
fileprivate func createEntryView() -> UIView
let date = DateFormatter.localizedString(from: Date(), dateStyle: .short, timeStyle: .none)
let number = UUID().uuidString
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .center
stack.distribution = .fillProportionally
stack.spacing = 8
let dateLabel = UILabel()
dateLabel.text = date
dateLabel.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
let numberLabel = UILabel()
numberLabel.text = number
numberLabel.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.caption2)
numberLabel.setContentHuggingPriority(UILayoutPriorityDefaultLow - 1.0, for: .horizontal)
numberLabel.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh - 1.0, for: .horizontal)
let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Del", for: UIControlState())
deleteButton.addTarget(self, action: #selector(DynamStackVC.deleteStackView(_:)), for: .touchUpInside)
stack.addArrangedSubview(dateLabel)
stack.addArrangedSubview(numberLabel)
stack.addArrangedSubview(deleteButton)
return stack
【问题讨论】:
【参考方案1】:我通过在动态 stackView 中的所有按钮和标签上添加背景颜色来解决这个问题。正如您在新的动画 gif 中所见,“添加项目”按钮的青色在第一次按下按钮后消失。为了确认,我将按钮的原始高度加倍(即,从 gif 左侧的 (25) 到 (50)),然后允许按下两个按钮,然后它不再起作用并且青色背景消失。这教会了我很多关于动态 stackView 如何工作的知识,我希望它对其他人有所帮助。
【讨论】:
如果您的问题已解决,请将答案标记为已接受,以告知其他人您的问题已解决。 我在发布答案后立即尝试,但系统不允许我这样做,显示红色错误:“您可以在 2 天内接受自己的答案” 哦,对不起。那是我的缺点。我没有注意问题发布的时间。请尽可能将答案标记为已接受。谢谢!以上是关于按钮在编程动态 stackView (Swift) 中变为非活动状态的主要内容,如果未能解决你的问题,请参考以下文章
StackView 中的按钮约束(以 Swift 编程方式)
如何在swift中使用for循环将按钮添加到stackview?