if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction - could this mean something here?

后端 未结 2 1790
忘掉有多难
忘掉有多难 2020-12-17 03:36

I am trying to find why a collection of custom UIButtons does not work. In a version described in my earlier post I created a circle of UIButtons programmatically in Swift 3

相关标签:
2条回答
  • 2020-12-17 04:23

    Don't worry about the fences warning message. It seems to be harmless and not caused by anything you're doing.

    There are several problems with the code you posted:

    1. You create myView and constrain its center, but you don't give it any size constraints. Furthermore, myView is a local variable and you don't add any subviews to myView. So myView is an invisible, sizeless view with no contents. Why are you creating it at all?

    2. You're drawing your “uberCircle” using a bare shape layer. By “bare”, I mean there's no view whose layer property is that layer. Bare layers don't participate in autolayout.

    3. You compute the position of each button based on the center of the top-level view's bounds. You're doing this during viewDidLoad, but viewDidLoad is called before the top-level view has been resized to fit the current device. So your wheel won't even be centered at launch on some devices.

    4. You don't set any constraints on the buttons, or set their autoresizing masks. The result is that, when the device rotates, the top-level view resizes but each button's position (relative to the top-left corner of the top-level view) stays the same.

    5. Turning on the “Upside Down” checkbox is not sufficient to allow upside-down orientation on iPhones, only on iPads.

    Here are the changes you need to make:

    1. Use a view to draw the “uberCircle”. If you want to use a shape layer, make a subclass of UIView that uses a CAShapeLayer for its layer. You can copy the ShapeView class from this answer.

    2. Set constraints from the center of the uberCircle to the center of the top-level view, to keep the uberCircle centered when the top-level view changes size.

    3. For each button, set constraints from the center of the button to the center of the top-level view, to keep the button positioned properly when the top-level view changes size. These constraints need non-zero constants to offset the buttons from the center.

    4. Override supportedInterfaceOrientations to enable upside-down orientation (in addition to checking the “Upside Down” checkbox).

    5. Get rid of myView in viewDidLoad. You don't need it.

    6. Get rid of the centre property. You don't need it.

    Thus:

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            createUberCircle()
            createButtons()
        }
    
        override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .all }
    
        private let radius: CGFloat = 96
        private let buttonCount = 10
        private let buttonSideLength: CGFloat = 60
    
        private func createUberCircle() {
            let circle = ShapeView()
            circle.translatesAutoresizingMaskIntoConstraints = false
            circle.shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: -radius, y: -radius, width: 2*radius, height: 2*radius)).cgPath
            circle.shapeLayer.fillColor = UIColor.cyan.cgColor
            view.addSubview(circle)
            circle.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            circle.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        }
    
        private func createButtons() {
            for i in 1 ... buttonCount {
                createButton(number: i)
            }
        }
    
        private func createButton(number: Int) {
            let button = UIButton(type: .custom)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = .white
            button.layer.cornerRadius = buttonSideLength / 2
            button.layer.borderWidth = 1
            button.layer.borderColor = UIColor.black.cgColor
            button.clipsToBounds = true
            button.titleLabel!.font = UIFont.systemFont(ofSize: buttonSideLength / 2)
            button.setTitleColor(.red, for: .normal)
            button.setTitle(String(number), for: .normal)
            view.addSubview(button)
    
            let radians = 2 * CGFloat.pi * CGFloat(number) / CGFloat(buttonCount) - CGFloat.pi / 2
            let xOffset = radius * cos(radians)
            let yOffset = radius * sin(radians)
            NSLayoutConstraint.activate([
                button.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: xOffset),
                button.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: yOffset),
                button.widthAnchor.constraint(equalToConstant: buttonSideLength),
                button.heightAnchor.constraint(equalToConstant: buttonSideLength)
                ])
        }
    
    }
    
    class ShapeView: UIView {
    
        override class var layerClass: Swift.AnyClass { return CAShapeLayer.self }
    
        lazy var shapeLayer: CAShapeLayer = { self.layer as! CAShapeLayer }()
    
    }
    
    0 讨论(0)
  • 2020-12-17 04:24

    I'd just constrain the parent UIView and constrain all of the buttons to the center of the parent view and override layoutSubviews. In layout subviews you can manipulate .constant of the centerX and centerY constraints for the buttons to reposition them. Alternatively you can just center all of them and use the .transform property of each button to move them into place.

    0 讨论(0)
提交回复
热议问题