Кнопка удержания изображения внутри UIImageView - PullRequest
0 голосов
/ 12 апреля 2020

У меня есть UIImageView, и пользователь может настроить изображение таким образом, чтобы width/height варьировалось. Я хотел бы добавить «x» - button в верхний правый угол, но НЕ из UIImageView, а из фактического image.

Вот как это выглядит прямо сейчас. Вся картинка - UIImageView, слева вы видите image, а в правом верхнем углу - button.

enter image description here

Вот как я ограничиваю это в данный момент:

theStackView.addArrangedSubview(self.imageView)
imageContainerView.addSubview(wishImageView)
imageContainerView.addSubview(deleteImageButton)

imageContainerView.heightAnchor.constraint(equalToConstant: 60).isActive = true
imageContainerView.isHidden = true

wishImageView.leadingAnchor.constraint(equalTo: imageContainerView.leadingAnchor, constant: 20).isActive = true
wishImageView.topAnchor.constraint(equalTo: imageContainerView.topAnchor, constant: 3).isActive = true
wishImageView.bottomAnchor.constraint(equalTo: imageContainerView.bottomAnchor, constant: 3).isActive = true
wishImageView.trailingAnchor.constraint(equalTo: imageContainerView.trailingAnchor, constant: -20).isActive = true

deleteImageButton.widthAnchor.constraint(equalToConstant: 10).isActive = true
deleteImageButton.heightAnchor.constraint(equalToConstant: 10).isActive = true
deleteImageButton.topAnchor.constraint(equalTo: wishImageView.topAnchor, constant: 5).isActive = true
deleteImageButton.trailingAnchor.constraint(equalTo: wishImageView.trailingAnchor, constant: -5).isActive = true

Это, очевидно, неправильно, но есть ли способ ограничить его фактическим image?

Ответы [ 2 ]

1 голос
/ 13 апреля 2020

Я собрал пример проекта, репо которого здесь .

В основном вам нужно сделать несколько вещей:

  • Рассчитать оба ваш UIImageView размер кадра вместе с рамкой UIMage, отображаемой в scaledAspectFit.
  • Создайте два именованных ограничения и динамически переместите вашу кнопку, как только у вас будет ее рамка.

Во-первых, вы должны помнить, что кадры не могут быть установлены до viewDidLayoutSubviews. Я создаю расширение UIImageView, которое легко вычисляет, где на самом деле находится кадр UIImage. (Это старый, но работающий код. Я уверен, что его можно улучшить.)

extension UIImageView {
    public var scaleFactor:CGFloat {
        guard let image = self.image, self.frame != CGRect.zero  else {
            return 0.0
        }

        let frame = self.frame
        let extent = image.size
        let heightFactor = frame.height/extent.height
        let widthFactor = frame.width/extent.width

        if extent.height > frame.height || extent.width > frame.width {
            if heightFactor < 1 && widthFactor < 1 {
                if heightFactor > widthFactor {
                    return widthFactor
                } else {
                    return heightFactor
                }
            } else if extent.height > frame.height {
                return heightFactor
            } else {
                return widthFactor
            }
        } else if extent.height < frame.height && extent.width < frame.width {
            if heightFactor < widthFactor {
                return heightFactor
            } else {
                return widthFactor
            }
        } else {
            return 1
        }
    }

    public var imageSize:CGSize {
        if self.image == nil {
            return CGSize.zero
        } else {
            return CGSize(width: (self.image?.size.width)!, height: (self.image?.size.height)!)
        }
    }

    public var scaledSize:CGSize {
        guard let image = self.image, self.frame != CGRect.zero  else {
            return CGSize.zero
        }
        let factor = self.scaleFactor
        return CGSize(width: image.size.width * factor, height: image.size.height * factor)
    }
}

Для второго пункта необходимо создать две переменные типа NSConstraint. Я адаптировал мой ответ из двух лет go для этого:

var btnTop:NSLayoutConstraint!
var btnTrailing:NSLayoutConstraint!

И в `viewDidLoad:

button.heightAnchor.constraint(equalToConstant: 20).isActive = true
button.widthAnchor.constraint(equalToConstant: 20).isActive = true

btnTop = button.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 10)
btnTop.isActive = true
btnTrailing = button.trailingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: -10)
btnTrailing.isActive = true

Обратите внимание, что вам нужно кодировать два строки для каждого ограничения! Я так и не понял, почему, но если вы попытаетесь добавить свойство isActive с фактическим ограничением, компилятор не будет знать правильный тип переменной.

Теперь вы все вместе ie в viewDidLayoutSubviews:

let scaledSize = imageView.scaledSize
var imageFrame = CGRect(origin: CGPoint.zero, size: scaledSize)
if scaledSize.width == imageView.frame.width {
    // image fills view along width, calculate Y constant
    imageFrame.origin.y = (imageView.frame.height - scaledSize.height) / 2
} else {
    // image fills view along height, calculate X constant
    imageFrame.origin.x = (imageView.frame.width - scaledSize.width) / 2
}
//btnTop.constant = imageFrame.width - 30
btnTop.constant = imageFrame.origin.y + 10
btnTrailing.constant = ((imageView.frame.width - imageFrame.width - imageFrame.origin.x) * -1) - 10

Поместить кнопку в верхнем левом углу на намного проще - мне потребовалось добрых 20 минут, чтобы получить правильные расчеты, чтобы сделать их сверху справа!

В моем тестовом проекте я инкапсулировал этот код в repositionCloseButton(), который будет вызываться каждый раз, когда приложение отображает новое изображение. Это должно работать как в портретной и альбомной ориентации, так и в портретной и альбомной ориентации - расположение кнопки закрытия 20x20 на расстоянии 10 точек от правого верхнего угла изображения.

1 голос
/ 12 апреля 2020

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

 let imgWidth = iv.image?.size.width

    NSLayoutConstraint.activate([
        iv.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        iv.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        iv.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        iv.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),

        btn.widthAnchor.constraint(equalToConstant: 20),
        btn.heightAnchor.constraint(equalToConstant: 20),
        btn.leadingAnchor.constraint(equalTo: iv.leadingAnchor , constant: (imgWidth ?? 0) > iv.frame.width ? iv.frame.width-20 : imgWidth ?? 0),
 //The issue happen when Image width is larger than the your imageview.Validate it for better result.
        btn.topAnchor.constraint(equalTo: iv.topAnchor,constant: 10)

    ])

Result

...