Почему UIView не остается в центре, пока он вращается?
Я пытаюсь откалибровать UIView, чтобы оставаться в центре, когда он вращается. Это следует за проблемой, выявленной наилучшими ответами на мой предыдущий вопрос . С тех пор я разработал код, основанный на одном ответе, предлагающем использовать viewWillAppear
или viewDidLayoutSubviews
вместо viewDidLoad
.
Поскольку я новичок в Swift, мне пришлось вернуться к учебнику Swift. Внедрение пользовательского элемента управления, в котором описывается, как сделать subClass из UIView . Мой код может рисовать круг, используя любую из трех функций: viewWillAppear
, viewDidLayoutSubviews
или viewDidLoad
.
Однако, когда я визуализую код, круг не всегда остается в центре, когда экран вращается. Ниже приведены последовательные вращения, которые происходят с использованием viewDidLoad
или viewWillAppear
Когда приложение запускается на экране в портретной ориентации, проблема возникает сразу же после первого поворота, независимо от того, влево или вправо. Если запустить в альбомной ориентации, можно пропустить проблему, если вы не пробовали хотя бы четыре последовательных вращения.
- Как вставить временную метку сервера firebase с помощью SDK iOS в проекте Swift
- Как возможен сильный цикл сохранения с помощью асинхронных или статических вызовов?
- Динамический UITableViewCell не изменяет размер в соответствии с содержимым
- Диаграммы классов UML для Xcode (быстрое программирование)
- Когда / What / Why / Как использовать значение UIApplicationOptionsURLKey из launchOptions в приложении (приложение: willFinishLaunchingWithOptions :)?
Ниже приведены последовательные повороты, которые происходят с использованием viewDidLayoutSubviews
где поворот иногда приводит к тому, что viewDidLayoutSubviews
круг накладывается на нецентральный круг. Это может произойти после нескольких поворотов, но для того, чтобы заметить проблему, нужно выполнить по крайней мере четыре оборота.
Вот код для CircleView
– моя попытка создать подкласс UIView
import UIKit class CircleView: UIView { let radius = CGFloat(200) let x: CGFloat = 0 let y: CGFloat = 0 // MARK: Initialization required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override init(frame: CGRect) { super.init(frame: frame) setup() } func setup() { // Create a CAShapeLayer let shapeLayer = CAShapeLayer() // The Bezier path that we made needs to be converted // to a CGPath before it can be used on a layer. shapeLayer.path = createBezierPath().cgPath // apply other properties related to the path shapeLayer.strokeColor = UIColor.red.cgColor shapeLayer.fillColor = UIColor.white.cgColor shapeLayer.lineWidth = 8.0 // add the new layer to our custom view self.layer.addSublayer(shapeLayer) } func createBezierPath() -> UIBezierPath { // create a new path let path = UIBezierPath(arcCenter: CGPoint(x: x, y: y), radius: radius, startAngle: CGFloat(M_PI * -0.5), endAngle:CGFloat(M_PI * 1.5), clockwise: true) path.fill() path.stroke() return path } }
и вот код для ViewController
import UIKit class ViewController: UIViewController { var circle: CircleView? var x: CGFloat? var y: CGFloat? override func viewDidLoad() { super.viewDidLoad() let centre = centreCircle() // create a new UIView and add it to the view controller let circleView = CircleView() circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0) view.addSubview(circleView) } func centreCircle() -> CGPoint { circle?.bounds = UIScreen.main.bounds return CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY) } }
И вот код для расширения UIScreen, который возвращает центральную точку экрана
import UIKit extension UIScreen { var centre: CGPoint { return CGPoint(x: bounds.midX, y: bounds.midY) } }
Чтобы произвести вышеупомянутые вращения, я заменил функцию viewWillAppear
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let centre = centreCircle() // create a new UIView and add it to the view controller let circleView = CircleView() circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0) view.addSubview(circleView) }
или viewDidLayoutSubviews
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() let centre = centreCircle() // create a new UIView and add it to the view controller let circleView = CircleView() circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0) view.addSubview(circleView) }
Может ли кто-нибудь увидеть проблему в моем коде, которая может остановить работу от работы?
- Как я могу добавить ссылку для кнопки скорости с быстрым?
- Динамически изменять текст заголовка раздела в статической ячейке
- Расширение класса для соответствия протокола NSCoding
- Когда я могу активировать / деактивировать ограничения макета?
- swift - сортировка массива объектов по их необязательному логическому свойству без принудительной развертки
- Управление клавишей «Tab» с внешней клавиатурой в iOS
- PGQueryTableViewController pagination не работает с heightForRowAtIndexPath
- как изменить размер шрифта uilabel в разных iPhone
Прежде всего, представление не выложено должным образом в viewdidload и viewwillappear, и вы явно определяете фрейм со значениями, что я считаю крайне расстраивающим, как новый программист. Это все еще раздражает меня, особенно когда речь заходит об изменении размеров меток. Таким образом, ваш взгляд и центральное окно centreX и centreY означают, что ваш взгляд будет придерживаться в тот момент, когда вы вращаетесь.
Исправьте это, изучив автозапуск. Сначала это отстой, но в конечном итоге это облегчит вашу жизнь. Взгляните на метод в этом расширении. Я использую его, когда хочу сосредоточить взгляд на другом представлении
extension UIView { func constrainAndCenter(in view: UIView, withRelativeHeight: CGFloat, withRelativeWidth: CGFloat) -> [NSLayoutConstraint] { self.translatesAutoresizingMaskIntoConstraints = false let x = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0) let w = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: withRelativeWidth, constant: 0) let h = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: view, attribute: .height, multiplier: withRelativeHeight, constant: 0) let y = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0) return ([x,w,h,y]) } } // then in viewdidload or whereever let circleView = CircleView() let circleViewConstraints = circleView.constrainAndCenter(in: view,....) view.addSubview(circleView) NSLayoutConstraint.activate(circleViewConstraints)
Это приколот к середине. Вы также можете сделать это в построителе интерфейса.
вы должны заменить frame.bounds
на frame.center
чтобы центр был рассчитан правильно.