если мы находимся в реальном обработчике предварительной фиксации, мы не можем добавить новые ограждения из - за ограничения CA-может ли это что-то значить здесь?



Я пытаюсь найти, почему коллекция пользовательских кнопок UIButtons не работает. В версии , описанной в моем предыдущем посте , я создал круг UIButtons программно в Swift 3 и закрепил круг в центре экрана. Эта версия использовала подкласс UIView-основанный на учебнике Apple Swift (реализовать Действие кнопки ) - вместе с реализацией autolayout, которая использует превосходный код Imanou Petit примеры (№6 якорь ). В этой версии мне удалось заставить мои кнопки успешно вращаться, когда iPhone вращается, но кнопка action-target не работает.



Итак, теперь я попробовал альтернативную версию, используя 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***


Сообщение происходит три раза из четырех, то есть нет никакого сообщения, когда телефон перевернут вверх дном. Это происходит, когда я запускаю либо код в моем предыдущем посте, либо код , показанный ниже. И в каждом случае не имело значения, была ли перевернутая коробка отмечена или не отмечена.

Введите описание изображения здесь
Я также попытался отключить режим OS_ACTIVITY , но это ничего не изменило за исключением скрытия сообщения, которое потенциально может объяснить проблему. Кто-то более опытный, чем я, надеюсь, поймет, что означает это сообщение отладки либо в контексте моего предыдущего кода (, показанного здесь), либо моего последнего кода, , показанного ниже.



ИСХОДНЫЙ КОД



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. Любое предложение приветствуется. Спасибо.



Решение



Сообщение, которое появилось в области отладки Xcode - и которое я использовал в теме этого сообщения-явно не было проблемой. Благодаря Робу Майоффу NSLayoutConstraint теперь вычисляет размеры и положение каждой кнопки, тогда как они были вычислены до времени выполнения в моем исходном коде. Его решение наряду с несколькими другими улучшения теперь отражены в приведенном ниже коде. К этому я добавил оригинальное действие-мишень для кнопок. Они не только работают, но и остаются привязанными к центру изображения всякий раз, когда меняется ориентация устройства.

Код можно легко заставить работать для другой конфигурации размера, изменив значения для radius, 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 }()
}
539   2  

2 ответов:

Не беспокойтесь о предупреждающем сообщении о заборах. Это кажется безвредным и не вызвано ничем, что вы делаете.

Есть несколько проблем с кодом, который вы опубликовали:

  1. Вы создаете myView и ограничиваете его центр, но не даете ему никаких ограничений по размеру. Кроме того, myView является локальной переменной, и вы не добавляете никаких вложенных представлений в myView. Таким образом, myView - это невидимое, безразмерное представление без содержания. Зачем вы вообще его создаете?

  2. Ты ... нарисуйте свой "uberCircle", используя голый слой формы. Под "голым" я подразумеваю отсутствие представления, чьим layer свойством является этот слой. Голые слои не участвуют в режим.

  3. Вы вычисляете положение каждой кнопки на основе центра границ представления верхнего уровня. Вы делаете это во время viewDidLoad, но viewDidLoad вызывается до того, как вид верхнего уровня был изменен в соответствии с текущим устройством. Так что ваше колесо даже не будет центрировано при запуске на некоторых устройствах.

  4. Ты ... не установлено каких-либо ограничений на кнопки, или установить их функциями автоматического изменения маски. В результате при вращении устройства вид верхнего уровня изменяется, но положение каждой кнопки (относительно левого верхнего угла вида верхнего уровня) остается неизменным.

  5. Включение флажка "вверх ногами" недостаточно, чтобы разрешить ориентацию вверх ногами на iPhone, только на iPad.

Вот изменения, которые вам нужно сделать:

  1. Используйте вид, чтобы нарисовать "uberCircle". Если вы хотите использовать слой формы, создайте подкласс UIView, который использует CAShapeLayer для своего слоя. Вы можете скопировать класс ShapeView из этого ответа.

  2. Установите ограничения от центра uberCircle к центру вида верхнего уровня, чтобы сохранить ubercircle центрированным, когда вид верхнего уровня изменяет размер.

  3. Для каждой кнопки установите ограничения от центра кнопки до центра представления верхнего уровня, чтобы сохранить кнопку правильно позиционируется, когда вид верхнего уровня меняет размер. Эти ограничения требуют ненулевых констант для смещения кнопок от центра.

  4. Переопределите supportedInterfaceOrientations, чтобы включить ориентацию вверх ногами (в дополнение к установке флажка "вверх ногами").

  5. Избавьтесь от myView в viewDidLoad. Тебе это не нужно.

  6. Избавьтесь от свойства centre. Тебе это не нужно.

Таким образом:

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

}

Я бы просто ограничил Родительский UIView и ограничил все кнопки в центре родительского представления и переопределил layoutSubviews. В подвидах макета вы можете манипулировать .константа ограничений centerX и centerY для кнопок для их перемещения. В качестве альтернативы вы можете просто центрировать все из них и использовать .преобразуйте свойство каждой кнопки, чтобы переместить их на место.

Comments

    Ничего не найдено.