【问题标题】:Problems with „Start Developing iOS Apps“-Guide after Upgrading to Swift 3: Rating Control not visible“开始开发 iOS 应用程序”的问题 - 升级到 Swift 3 后的指南:评级控制不可见
【发布时间】:2016-09-18 17:24:39
【问题描述】:

随着 Swift 3.0Xcode 8.0 的发布,我决定看看我最近在 Apple 的 自己的项目之后构建的一个项目指导Start Developing iOS Apps (Swift) - 您可以下载示例项目here

在转换为当前的 Swift 语法并对项目进行一些小的调整后,代码编译没有错误,应用程序运行完美,除了 RatingControl.swift 中定义的自定义控件不可见。使用 Interface Builder 将视图移出堆栈视图会使其可见,但一旦添加约束,它就会再次消失。

是bug还是代码需要进一步调整?

为了完整起见:代码是自动转换的,Privacy Photo Library Usage Description 被添加到 Info.plist,强制展开在 saveMeals()loadMeals() 中被移除,额外的向下转换被添加到位于 prepare(for:sender:) 中的 MealViewController.swift .

提前谢谢你。


界面生成器


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
        }
    }
}

【问题讨论】:

    标签: swift xcode uikit interface-builder


    【解决方案1】:

    答案有点长,但我会尝试给出简短的版本:当您将旧情节提要转换为使用初始设备大小的模板时,最新的 Xcode 中有一个新行为。当控制器点击viewDidLoad时,控制器主视图的子视图的帧还没有计算出它们的初始帧,并且都是1000x1000的大小。这会抛出一些运行良好的 UI,直到您在 Xcode 8.0 中将它们转换为 IB - 尤其是当您需要知道按钮的高度以计算其角半径时。在许多情况下,在修改这些视图之前简单地调用self.view.layoutIfNeeded() 即可解决问题,但在本项目中并非如此。

    我不打算详细说明这一点,因为坦率地说,我仍然习惯这些问题 - 在我的项目中,我会逐案处理。

    有问题的项目使用堆栈视图/某些自动布局/内容模式的组合,这会导致奇怪的行为:在您引用的控制器上,问题似乎是容器堆栈视图不知道评级控件的高度。

    我尝试了几件事:首先,我在评级控件中添加了 44.0 的高度约束。这让它看起来,但宽度是错误的 - 它与堆栈视图的宽度匹配,并且评级控件左对齐而不是居中。

    最终奏效的是:

    • 在堆栈视图中添加容器视图并将其高度设置为 44.0
    • 使评级控件成为该容器视图的子视图
    • 向 Rating 控件添加宽度和高度限制 (240.0 x 44.0)
    • 在其父视图上水平和垂直居中评级控件

    需要注意的一点:不设置宽度约束也会导致奇怪的行为 - 评级控件的宽度由于某种原因变得非常大。

    我不知道这是否是您问题的最终答案,但这似乎已经成功了。如果有帮助,您可以找到project I edited here。我为容器视图和评级控件添加了背景颜色/边框颜色,以实现更好的可视化。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多