Маска UIView с другим UIView - PullRequest
       40

Маска UIView с другим UIView

0 голосов
/ 11 ноября 2018

Да, этот вопрос уже задавался, решения не работали или имели разные приложения.

Это самая базовая настройка. У меня есть два прямоугольных UIViews, красный и синий. Я бы хотел, чтобы синий квадрат врезался в красный, поэтому красный квадрат выглядит как "L"

enter image description here

import Foundation
import UIKit

class TestController: UIViewController {
    override func viewDidLoad() {
        view.backgroundColor = .gray
        view.addSubview(viewA)
        view.addSubview(maskView)

        viewA.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        viewA.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        viewA.widthAnchor.constraint(equalToConstant: 100).isActive = true
        viewA.heightAnchor.constraint(equalToConstant: 100).isActive = true
        viewA.translatesAutoresizingMaskIntoConstraints = false

        maskView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 50).isActive = true
        maskView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50).isActive = true
        maskView.widthAnchor.constraint(equalToConstant: 100).isActive = true
        maskView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        maskView.translatesAutoresizingMaskIntoConstraints = false

        // Things which don't work
        //viewA.mask = maskView // both views disappear
        //viewA.layer.mask = maskView.layer // both views disappear
        //viewA.layer.addSublayer(maskView.layer) // hides mask view
    }

    var viewA: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        view.layer.masksToBounds = true
        return view
    }()

    var maskView: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        return view
    }()
}

Это результат, который я ожидаю: (сделано в Photoshop)

enter image description here

1 Ответ

0 голосов
/ 12 ноября 2018

Поскольку в iOS нет волшебного способа маскировки, я представлю здесь простой способ добиться этого.

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

Нетрудно изменить подкласс UIViews для ваших собственных целей, особенно для представлений.

    import UIKit

        class TestController: UIViewController {

                override func viewDidLoad() {
                    view.backgroundColor = .gray
                    view.addSubview(viewA)
                    view.addSubview(maskView)
                    maskView.maskedView = viewA
                    viewA.activeMask = maskView
                    viewA.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
                    viewA.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
                    viewA.widthAnchor.constraint(equalToConstant: 100).isActive = true
                    viewA.heightAnchor.constraint(equalToConstant: 100).isActive = true
                    viewA.translatesAutoresizingMaskIntoConstraints = false
                    maskView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 50).isActive = true
                    maskView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50).isActive = true
                    maskView.widthAnchor.constraint(equalToConstant: 100).isActive = true
                    maskView.heightAnchor.constraint(equalToConstant: 100).isActive = true
                    maskView.translatesAutoresizingMaskIntoConstraints = false
                }

                var viewA: MyUIView = {
                    let view = MyUIView()
                    view.backgroundColor = .clear
                    view.layer.masksToBounds = true
                    return view
                }()


            var maskView: ActiveMaskView = {
                let view = ActiveMaskView()
                    view.backgroundColor = .clear
                    return view
                }()


            }

        class ActiveMaskView: UIView{
            override func didMoveToSuperview() {
                super.didMoveToSuperview()
                let panGesture =  UIPanGestureRecognizer.init(target: self, action: #selector(moveAround(_:)))
                self.addGestureRecognizer(panGesture)
            }
              weak  var maskedView : UIView?
            private var frameOrigin : CGPoint = CGPoint.zero

          @objc  func moveAround(_ panGesture: UIPanGestureRecognizer){
            guard let superview = superview else {return}
                switch panGesture.state {
                case .began:
                  frameOrigin = frame.origin
                    self.backgroundColor = UIColor.blue
                case .changed:
                    let translation  = panGesture.translation(in: superview)
                    frame = CGRect.init(origin: CGPoint.init(x: frameOrigin.x + translation.x, y: frameOrigin.y + translation.y), size: frame.size)
                    maskedView?.setNeedsDisplay()
                    break
                case .ended:
                    self.backgroundColor =
                        frame.intersects(maskedView!.frame) ?
                    UIColor.clear : UIColor.blue
                    maskedView?.setNeedsDisplay()
                case .cancelled:
                    frame = CGRect.init(origin: frameOrigin , size: frame.size)
                    self.backgroundColor =
                        frame.intersects(maskedView!.frame) ?
                    UIColor.clear : UIColor.blue
                    maskedView?.setNeedsDisplay()
                default:
                    break;
                }
            }
        }

        class MyUIView: UIView{

          weak  var activeMask: ActiveMaskView?

            override func draw(_ rect: CGRect) {
                super.draw(rect)
                let ctx = UIGraphicsGetCurrentContext()
                ctx?.setFillColor(UIColor.red.cgColor)
                ctx?.fill(self.layer.bounds)
                ctx?.setBlendMode(.sourceOut)
                guard let activeMask = activeMask , let superview = superview else {
                   return
                }
              let sc = frame.intersection(activeMask.frame)
            let interSection = superview.convert(sc, to: self)
                ctx?.fill(interSection )
             }
        }
...