Как мне сохранить положение и размер изображений постоянными между этими UIImageViews? - PullRequest
0 голосов
/ 12 января 2020

enter image description here

У меня есть эта сцена неоновых кассет, как вы видите. В конструкторе интерфейсов я создал 3 UIImageViews, один для фона кассеты и 2 для левого и правого шпинделей. Идея состоит в том, что эти шпиндели вращаются назад или вперед в зависимости от состояния (перемотка назад, ffw или игра). Я могу сделать это нормально в случае, если я запускаю это исключительно, скажем, на iPhone 8. Однако, когда я решаю, что хочу запустить это на iPhone 11 Pro, происходит следующее:

enter image description here

Независимо от того, какую причудливую смесь ограничений я пытаюсь придумать, я не могу заставить шпиндели следовать их правильному положению / размеру на разных устройствах. Мне придется потратить некоторое время на поиск и чтение руководств по зверю, который является Auto Layout, но до тех пор, пока не поднимется эта гора, я буду признателен за любую помощь!

РЕДАКТИРОВАТЬ:

Вот программа c, более наглядная, версия того, что у меня есть:

override func viewDidLoad() {
    super.viewDidLoad()

    // Code to position/size cassette
    let cassette = UIImageView(image: UIImage(named: "cassette"))
    cassette.translatesAutoresizingMaskIntoConstraints = false
    cassette.contentMode = .scaleAspectFit
    view.addSubview(cassette)

    view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: cassette.bottomAnchor, constant: 44).isActive = true
    view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: cassette.trailingAnchor, constant: 20).isActive = true
    cassette.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
    cassette.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 44).isActive = true

    // Code to position/size spindles
    let spindleLeft = UIImageView(image: UIImage(named: "spindle"))
    spindleLeft.translatesAutoresizingMaskIntoConstraints = false
    spindleLeft.widthAnchor.constraint(equalToConstant: 74).isActive = true
    spindleLeft.heightAnchor.constraint(equalToConstant: 74).isActive = true
    cassette.addSubview(spindleLeft)

    spindleLeft.centerXAnchor.constraint(equalTo: cassette.centerXAnchor, constant: -130.0).isActive = true
    spindleLeft.centerYAnchor.constraint(equalTo: cassette.centerYAnchor, constant: -14.0).isActive = true

}

Вот 2 ресурса: enter image description here enter image description here

В настоящее время я застрял, пытаясь выяснить, есть ли какой-либо способ использовать aspectRatio устройства и какой режим содержимого UIImageView (Aspect Fit, Aspect Fill) мне следует использовать. Возможно, я выкопал слишком глубоко, и есть гораздо более простой способ справиться с этим, которого я не вижу ...

Ответы [ 2 ]

1 голос
/ 13 января 2020

Простое autolayout не собирается делать это. Вы должны измерить, где был бы шпиндель, если бы он был частью исходного изображения, а затем математически поместить туда шпиндель, исходя из фактического размера представления изображения и места, в котором он помещает изображение в режиме содержимого.

Давайте сделаем это для одного шпинделя (левый шпиндель). Размещенное вами изображение кассеты 4824x2230. При тщательном осмотре мы обнаруживаем, что если изображение на кассете было показано в полном размере, центр шпинделя должен быть приблизительно (1294,1000), и он должен быть около 500 пикселей сбоку.

то же самое, что сказать, что мы хотим, чтобы изображение шпинделя занимало квадрат, чья рамка (относительно исходного изображения кассеты) равна (1045 750 500 500).

Хорошо, но это только изображение. Мы должны расположить шпиндель относительно изображения, которое его изображает.

Итак, сейчас я покажу кассету в виде изображения, размер которого определяется путем автоматического размещения до некоторого меньшего размера. (Я могу узнать , какой размер в viewDidLayoutSubviews, который запускается после того, как autolayout сделал свою работу.) И пусть это представление изображения имеет режим содержимого Aspect Fit. Размер изображения будет изменен, а также его положение, вероятно, не будет в исходной точке просмотра изображения.

Итак, проблема, которую вы должны решить (в коде): теперь, где находится рамка шпинделя относительно вида изображения после изменения размера и изменения положения изображения? Затем вы просто помещаете туда вид изображения шпинделя.

Вот код из viewDidLayoutSubviews; cassette - это вид изображения кассеты, spindle - это вид изображения шпинделя:

    let cassettebounds = cassette.bounds
    let cw = cassettebounds.width
    let ch = cassettebounds.height
    let w = 4824 as CGFloat
    let h = 2230 as CGFloat
    var scale = cw/w
    var imw = cw
    var imh = h*scale
    var imx = 0 as CGFloat
    var imy = (ch-imh)/2
    if imh > ch { // we got it backwards
        scale = ch/h
        imh = ch
        imw = w*scale
        imy = 0 as CGFloat
        imx = (cw-imw)/2
    }
    cassette.addSubview(spindle)
    spindle.frame.size.width = 500*scale
    spindle.frame.size.height = 500*scale
    spindle.frame.origin.x = imx + (1045*scale)
    spindle.frame.origin.y = imy + (750*scale)

Вот результат для 6s и 11 Pro:

enter image description here

enter image description here

Выглядит чертовски хорошо, если я сам так скажу. Правый шпиндель оставлен в качестве упражнения для читателя.

0 голосов
/ 13 января 2020

Спасибо @matt за его превосходный ответ. Я определенно приписывал слишком большую мощность автоматической компоновке, когда требовался более элементарный подход. Я отметил его ответ правильно и предоставлю мой новый код, который работает и поддерживает экраны всех размеров:

override func viewDidLoad() {
    super.viewDidLoad()

    // Code to position/size cassette
    cassette = UIImageView(image: UIImage(named: "cassette"))
    cassette.translatesAutoresizingMaskIntoConstraints = false
    cassette.isUserInteractionEnabled = true
    cassette.contentMode = .scaleAspectFit
    view.addSubview(cassette)

    view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: cassette.bottomAnchor, constant: 44).isActive = true
    view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: cassette.trailingAnchor, constant: 20).isActive = true
    cassette.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
    cassette.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 44).isActive = true
}

override func viewDidLayoutSubviews() {
    spindleLeft = addSpindle(to: cassette, posX: 505, posY: 350)
    spindleRight = addSpindle(to: cassette, posX: 1610, posY: 350)
}

func addSpindle(to cassette: UIImageView, posX: CGFloat, posY: CGFloat) -> UIImageView {
    let cassetteBounds = cassette.bounds
    let cassetteWidth = cassetteBounds.width
    let cassetteHeight = cassetteBounds.height

    let cassetteImageWidth =  cassette.image!.size.width
    let cassetteImageHeight = cassette.image!.size.height

    var scale = cassetteWidth / cassetteImageWidth

    var spindleWidth = cassetteWidth
    var spindleHeight = cassetteImageHeight*scale
    var spindleX = 0 as CGFloat
    var spindleY = (cassetteHeight - spindleHeight)/2

    if spindleHeight > cassetteHeight {
        scale = cassetteHeight / cassetteImageHeight
        spindleHeight = cassetteHeight
        spindleWidth = cassetteImageWidth*scale
        spindleY = 0 as CGFloat
        spindleX = (cassetteWidth - spindleWidth)/2
    }

    let spindle = UIImageView(image: UIImage(named: "spindle"))
    cassette.addSubview(spindle)

    spindle.frame.origin.x = spindleX + (posX*scale)
    spindle.frame.origin.y = spindleY + (posY*scale)
    spindle.frame.size.width = spindle.image!.size.width*scale //299.0
    spindle.frame.size.height = spindle.image!.size.height*scale //299.0

    return spindle
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...