Я пытаюсь найти, почему коллекция пользовательских UIButtons не работает. В версии описанной в моем предыдущем сообщении, я создал круг UIButtons programmatically в Swift 3 и привязали круг к центру экрана. В этой версии был использован подкласс UIView - на основе учебника Apple Swift (реализация действия кнопки) - вместе с реализацией автозапуска, которая опирается на Imanou Petits отлично примеры кода (No.6 Anchor). В этой версии мне удалось заставить мои кнопки успешно вращаться, когда iPhone вращается, но действие-действие кнопки не работает.
Итак, теперь я попробовал альтернативную версию с помощью viewcontroller вместо подкласса UIView. На этот раз работает одна и та же кнопка-цель, но поворот телефона приводит к смещению изображения от центра, как показано ниже.
При каждом повороте в области отладки Xcode дважды появляется следующее сообщение.
***[App] if we're in the real pre-commit handler we can't
actually add any new fences due to CA restriction***
Сообщение происходит три раза из четырех, т.е. нет сообщения, когда телефон перевернут вверх дном. Это происходит, когда я запускаю код в своем предыдущем сообщении или код, показанный ниже. И в каждом случае не имело значения, было ли проверено или не проверено поле Upside Down.
Я также попробовал отключить OS_ACTIVITY MODE, но ничего не изменил, кроме как скрыть сообщение, которое потенциально может объяснить проблему. Кто-то более опытный, чем я, мы надеемся, узнаем, что это сообщение отладки означает либо в контексте моего предыдущего кода (показано здесь), либо мой последний код, показанный ниже.
ОРИГИНАЛЬНЫЙ КОД
import UIKit
class ViewController: UIViewController {
// MARK: Initialization
let points: Int = 10 // 80 25 16 10 5
let dotSize: CGFloat = 60 // 12 35 50 60 99
let radius: CGFloat = 48 // 72 70 64 48 42
var centre: CGPoint?
var arcPoint = CGFloat(M_PI * -0.5) // clockwise from 12+ (not 3+)!
override func viewDidLoad() {
super.viewDidLoad()
let myView = UIView()
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
centre = centrePoint()
let horizontalConstraint = myView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = myView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
drawUberCircle()
drawBoundaryCircles()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func drawUberCircle() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
// give Bezier path layer properties
shapeLayer.path = createBezierPath().cgPath
// apply layer properties
shapeLayer.strokeColor = UIColor.cyan.cgColor
shapeLayer.fillColor = UIColor.cyan.cgColor
shapeLayer.lineWidth = 1.0
// add layer
view.layer.addSublayer(shapeLayer)
}
func createBezierPath() -> UIBezierPath {
// create a new path
let path = UIBezierPath(arcCenter: centre!,
radius: radius * 2.0,
startAngle: CGFloat(M_PI * -0.5),
endAngle: CGFloat(M_PI * 1.5),
clockwise: true)
return path
}
func drawBoundaryCircles() {
for index in 1...points {
let point: CGPoint = makeBoundaryPoint(centre: centre!)
drawButton(point: point, index: index)
}
}
func makeBoundaryPoint(centre: CGPoint) -> (CGPoint) {
arcPoint += arcAngle()
print(arcPoint)
let point = CGPoint(x: centre.x + (radius * 2 * cos(arcPoint)), y: centre.y + (radius * 2 * sin(arcPoint)))
return (point)
}
func arcAngle() -> CGFloat {
return CGFloat(2.0 * M_PI) / CGFloat(points)
}
func centrePoint() -> CGPoint {
return CGPoint(x: view.bounds.midX, y: view.bounds.midY)
}
func drawButton(point: CGPoint, index: Int) {
let myButton = UIButton(type: .custom) as UIButton
myButton.frame = CGRect(x: point.x - (dotSize/2), y: point.y - (dotSize/2), width: dotSize, height: dotSize)
myButton.backgroundColor = UIColor.white
myButton.layer.cornerRadius = dotSize / 2
myButton.layer.borderWidth = 1
myButton.layer.borderColor = UIColor.black.cgColor
myButton.clipsToBounds = true
myButton.titleLabel!.font = UIFont(name: "HelveticaNeue-Thin", size: dotSize/2)
myButton.setTitleColor(UIColor.red, for: .normal)
myButton.setTitle(String(index), for: .normal)
myButton.tag = index;
myButton.sendActions(for: .touchUpInside)
myButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
view.addSubview(myButton)
}
func buttonAction(myButton: UIButton) {
let sender:UIButton = myButton
print("Button \(sender.tag) works")
}
}
Я все еще участвую в процессе обучения Swift, поэтому на данном этапе не имеет значения, использует ли решение viewcontroller или подкласс UIView, пока я могу организовать круг UIButtons, который все еще работает после того, как я настроил их с помощью autolayout. Каждое предложение приветствуется. Спасибо.
Решение
Сообщение, появившееся в области отладки Xcodes, и которое я использовал в строке темы этого сообщения, явно не было проблемой. Благодаря Rob Mayoff NSLayoutConstraint теперь вычисляет размеры и положение каждой кнопки, тогда как они были вычислены до времени выполнения в моем исходном коде. Его решение наряду с несколькими другими улучшениями теперь отражено в коде ниже. К этому я добавил исходную целевую кнопку для кнопок. Они не только работают, но и остаются заблокированными в центре просмотра всякий раз, когда меняется ориентация устройства.
Код может быть легко выполнен для работы с другой конфигурацией размера, изменяя значения радиуса, buttonCount и buttonSideLength (см. таблицу).
Вот код
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
createUberCircle()
createButtons()
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .all }
private let radius: CGFloat = 85
private let buttonCount = 5
private let buttonSideLength: CGFloat = 100
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
if buttonCount < 10 {
circle.shapeLayer.fillColor = UIColor.clear.cgColor
} else {
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)
if buttonCount > 25 {
button.setTitleColor(.clear, for: .normal)
} else {
button.setTitleColor(.red, for: .normal)
}
button.setTitle(String(number), for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button.tag = number
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)
])
}
func buttonAction(myButton: UIButton) {
let sender:UIButton = myButton
print("Button \(sender.tag) works")
}
}
class ShapeView: UIView {
override class var layerClass: Swift.AnyClass { return CAShapeLayer.self }
lazy var shapeLayer: CAShapeLayer = { self.layer as! CAShapeLayer }()
}