Как обрезать UIImage для маскировки в Swift - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть UIImage, который я маскирую, используя другой UIImage. Единственная проблема заключается в том, что область за пределами маскированного UIImage по-прежнему взаимодействует с пользователем. Как полностью обрезать UIImage к другому изображению вместо маски.

@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    let imageMask = UIImageView()

    imageMask.image = //image to mask

    imageMask.frame = photoImageView.bounds
    imageView.mask = imageMask
}

enter image description here enter image description here

1 Ответ

0 голосов
/ 02 декабря 2018

Критерии

Простой тестовый пример может определить цвет фона для представления ViewController и загрузить изображение и маску.Затем UITapGestureRecognizer добавляется в представление ViewController и в UIImageView.

При применении цвета фона к представлению ViewController легко увидеть, работает ли маскирование.

Если вы затем коснетесь непрозрачной области, касание должно быть получено UIImageViewв противном случае представление ViewController должно получить сигнал.

Размер изображения и изображения маски

В большинстве случаев размер изображения и изображения маски или, как минимум, соотношение сторон изображенияизображение и изображение маски одинаковы.Имеет смысл использовать тот же contentMode для маскировки UIImageView, что и для исходного UIImageView, в противном случае при изменении режима содержимого в InterfaceBuilder может произойти смещение не позднее.

Test Case

Поэтому контрольный пример может выглядеть следующим образом:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    private let maskView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.imageView.image = UIImage(named: "testimage")
        self.maskView.image = UIImage(named: "mask")
        self.imageView.mask = maskView

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
        self.view.addGestureRecognizer(tapGestureRecognizer)

        let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
        self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.maskView.contentMode = self.imageView.contentMode
        self.maskView.frame = self.imageView.bounds
    }

    @objc private func backgroundTapped() {
        print ("background tapped!")
    }

    @objc private func iamgeViewTapped() {
        print ("image view tapped!")
    }

}

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

CustomImageView

Поэтому нам нужен CustomImageView, который возвращает при нажатии на прозрачный пиксель, что он не отвечает за него.

Это может бытьдостигается путем переопределения этого метода:

func point(inside point: CGPoint, 
      with event: UIEvent?) -> Bool

см. документацию здесь: https://developer.apple.com/documentation/uikit/uiview/1622533-point

Возвращает логическое значение, указывающее, содержит ли получатель указанную точку.

На SO уже есть этот крутой ответ, который немного адаптирован: https://stackoverflow.com/a/27923457

import UIKit

class CustomImageView: UIImageView {

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        return self.alphaFromPoint(point: point) > 32
    }

    private func alphaFromPoint(point: CGPoint) -> UInt8 {
        var pixel: [UInt8] = [0, 0, 0, 0]
        let colorSpace = CGColorSpaceCreateDeviceRGB();
        let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        if let context = CGContext(data: &pixel,
                                   width: 1,
                                   height: 1,
                                   bitsPerComponent: 8,
                                   bytesPerRow: 4,
                                   space: colorSpace,
                                   bitmapInfo: alphaInfo.rawValue) {
            context.translateBy(x: -point.x, y: -point.y)
            self.layer.render(in: context)
        }
        return pixel[3]
    }

}

Не забудьте изменить пользовательский класс ImageView на CustomImageView в XCode в инспекторе идентичности.

Если вы теперь нажмете на прозрачные области, представление ViewController в фоновом режиме получает касание.Если вы нажмете на непрозрачные области, наш просмотр изображений получит касание.

Demo

Вот короткая демонстрация приведенного выше кода с использованием изображения и маски извопрос:

demo

...