随着 Swift 3.0 和 Xcode 8.0 的发布,我决定看看我最近在 Apple的之后建立的项目指南Start Developing iOS Apps (Swift) - 您可以下载示例项目here。
转换为当前 Swift 语法并对项目进行一些微小调整后,代码编译时没有错误,应用程序运行完美,除了RatingControl.swift
中定义的自定义控件不可见。使用 Interface Builder 将视图移出堆栈视图会使其可见,但只要添加约束,它就会再次消失。
这是一个错误还是代码需要进一步调整?
为了完整起见:代码已自动转换,Privacy Photo Library Usage Description
已添加到Info.plist
,强制展开已在saveMeals()
和loadMeals()
中删除,并添加了其他向下广播prepare(for:sender:)
位于MealViewController.swift
。
提前谢谢。
Interface Builder
RatingControl.swift
import UIKit
class RatingControl: UIView {
// MARK: Properties
var rating = 0 {
didSet {
setNeedsLayout()
}
}
var ratingButtons = [UIButton]()
var spacing = 5
var stars = 5
// MARK: Initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let filledStarImage = UIImage(named: "filledStar")
let emptyStarImage = UIImage(named: "emptyStar")
for _ in 0..<5 {
let button = UIButton()
button.setImage(emptyStarImage, for: UIControlState())
button.setImage(filledStarImage, for: .selected)
button.setImage(filledStarImage, for: [.highlighted, .selected])
button.adjustsImageWhenHighlighted = false
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), for: .touchDown)
ratingButtons += [button]
addSubview(button)
}
}
override func layoutSubviews() {
// Set the button's width and height to a square the size of the frame's height.
let buttonSize = Int(frame.size.height)
var buttonFrame = CGRect(x: 0, y: 0, width: buttonSize, height: buttonSize)
// Offset each button's origin by the length of the button plus spacing.
for (index, button) in ratingButtons.enumerated() {
buttonFrame.origin.x = CGFloat(index * (buttonSize + spacing))
button.frame = buttonFrame
}
updateButtonSelectionStates()
}
override var intrinsicContentSize : CGSize {
let buttonSize = Int(frame.size.height)
let width = (buttonSize + spacing) * stars
return CGSize(width: width, height: buttonSize)
}
// MARK: Button Action
func ratingButtonTapped(_ button: UIButton) {
rating = ratingButtons.index(of: button)! + 1
updateButtonSelectionStates()
}
func updateButtonSelectionStates() {
for (index, button) in ratingButtons.enumerated() {
// If the index of a button is less than the rating, that button should be selected.
button.isSelected = index < rating
}
}
}
答案 0 :(得分:2)
答案有点长,但我会尝试提供简短版本:当您将旧故事板转换为使用初始设备大小的模板时,最新Xcode中会出现一种新行为。当控制器命中viewDidLoad
时,控制器主视图的子视图的帧仍然没有计算它们的初始帧,并且所有帧的大小都是1000x1000。这会抛弃一些工作正常的UI,直到你在Xcode 8.0中将它们转换为IB - 特别是当你需要时,例如,知道按钮的高度来计算它的角半径。在许多情况下,在修改这些视图之前简单地调用self.view.layoutIfNeeded()
可以解决问题,但在这个项目中并非如此。
我不打算详细说明这一点,因为坦率地说,我仍然习惯于这些问题 - 在我的项目中,我会逐个处理它们。
有问题的项目正在使用堆栈视图/某些AutoLayout /内容模式的组合,这会导致一种奇怪的行为:在您引用的控制器上,问题似乎是容器堆栈视图并不知道评级控制的高度。
我尝试了一些方法:首先,我在评级控件中添加了44.0的高度限制。这样就显现了,但宽度错了 - 它与堆栈视图的宽度相匹配,并且评级控件左对齐而不是居中。
最终起作用的是:
需要注意的事项:没有设置宽度约束也会导致奇怪的行为 - 评级控制的宽度由于某种原因而疯狂。
我不知道这是否是你问题的最终答案,但这似乎已经成功了。如果有帮助,您可以找到project I edited here。我为容器视图和评级控件添加了背景颜色/边框颜色,以实现更好的可视化。
希望这会有所帮助。